diff --git a/av/codec/context.pyx b/av/codec/context.pyx
index 7e79b8266f037b11638f934149e78ffcaff159bc..9f5dc92b14f21ad13587b6dd5e46e831fbf9ff2e 100644
--- a/av/codec/context.pyx
+++ b/av/codec/context.pyx
@@ -157,6 +157,7 @@ cdef class CodecContext(object):
     cdef _init(self, lib.AVCodecContext *ptr, const lib.AVCodec *codec):
 
         self.ptr = ptr
+        self.ptr.opaque = <void*>self
         if self.ptr.codec and codec and self.ptr.codec != codec:
             raise RuntimeError('Wrapping CodecContext with mismatched codec.')
         self.codec = wrap_codec(codec if codec != NULL else self.ptr.codec)
diff --git a/av/video/codeccontext.pxd b/av/video/codeccontext.pxd
index 9693caa9bb91e111c0f0e1f44ec485665648a7b2..d142b442f5b062db985ad7620b619e9cf5b3bfc1 100644
--- a/av/video/codeccontext.pxd
+++ b/av/video/codeccontext.pxd
@@ -1,4 +1,5 @@
 
+cimport libav as lib
 from av.codec.context cimport CodecContext
 from av.video.format cimport VideoFormat
 from av.video.frame cimport VideoFrame
@@ -7,8 +8,9 @@ from av.video.reformatter cimport VideoReformatter
 
 cdef class VideoCodecContext(CodecContext):
 
-    cdef VideoFormat _format
-    cdef _build_format(self)
+    cdef lib.AVPixelFormat _preferred_format
+
+    cdef VideoFormat _last_format
 
     cdef int last_w
     cdef int last_h
diff --git a/av/video/codeccontext.pyx b/av/video/codeccontext.pyx
index f78e850e5c26ff08365a6a95436c4d16ce5a0eb3..28451904f19af71e8892098d9bbf9d99daf164c9 100644
--- a/av/video/codeccontext.pyx
+++ b/av/video/codeccontext.pyx
@@ -11,6 +11,14 @@ from av.video.format cimport get_video_format, VideoFormat
 from av.video.frame cimport VideoFrame, alloc_video_frame
 from av.video.reformatter cimport VideoReformatter
 
+cdef lib.AVPixelFormat get_format_callback(lib.AVCodecContext *ptr, const lib.AVPixelFormat *fmt):
+    cdef lib.AVPixelFormat pref = (<VideoCodecContext>ptr.opaque)._preferred_format
+    cdef int current = 0
+    while fmt[current] != -1:
+        if fmt[current] == pref:
+            return pref
+        current += 1
+    return lib.avcodec_default_get_format(ptr, fmt)
 
 cdef class VideoCodecContext(CodecContext):
 
@@ -20,8 +28,10 @@ cdef class VideoCodecContext(CodecContext):
 
     cdef _init(self, lib.AVCodecContext *ptr, const lib.AVCodec *codec):
         CodecContext._init(self, ptr, codec)  # TODO: Can this be `super`?
-        self._build_format()
+        self._last_format = None
         self.encoded_frame_count = 0
+        self._preferred_format = lib.AV_PIX_FMT_NONE
+        self.ptr.get_format = get_format_callback
 
     cdef _set_default_time_base(self):
         self.ptr.time_base.num = self.ptr.framerate.den or 1
@@ -36,7 +46,7 @@ cdef class VideoCodecContext(CodecContext):
 
         # Reformat if it doesn't match.
         if (
-            vframe.format.pix_fmt != self._format.pix_fmt or
+            vframe.format.pix_fmt != self.ptr.pix_fmt or
             vframe.width != self.ptr.width or
             vframe.height != self.ptr.height
         ):
@@ -46,7 +56,7 @@ cdef class VideoCodecContext(CodecContext):
                 vframe,
                 self.ptr.width,
                 self.ptr.height,
-                self._format,
+                self.format,
             )
 
         # There is no pts, so create one.
@@ -65,18 +75,30 @@ cdef class VideoCodecContext(CodecContext):
         cdef VideoFrame vframe = frame
         vframe._init_user_attributes()
 
-    cdef _build_format(self):
-        self._format = get_video_format(<lib.AVPixelFormat>self.ptr.pix_fmt, self.ptr.width, self.ptr.height)
-
     property format:
         def __get__(self):
-            return self._format
+            if not (
+                self._last_format != None and
+                self._last_format.pix_fmt == self.ptr.pix_fmt and
+                self._last_format.width == self.ptr.width and
+                self._last_format.height == self.ptr.height
+            ):
+                self._last_format = get_video_format(<lib.AVPixelFormat>self.ptr.pix_fmt, self.ptr.width, self.ptr.height)
+            return self._last_format
 
         def __set__(self, VideoFormat format):
             self.ptr.pix_fmt = format.pix_fmt
             self.ptr.width = format.width
             self.ptr.height = format.height
-            self._build_format()  # Kinda wasteful.
+
+    property preferred_format:
+        def __get__(self):
+            if self._preferred_format == lib.AV_PIX_FMT_NONE:
+                return None
+            return lib.av_get_pix_fmt_name(self._preferred_format)
+
+        def __set__(self, value):
+            self._preferred_format = lib.av_get_pix_fmt(value)
 
     property width:
         def __get__(self):
@@ -84,7 +106,6 @@ cdef class VideoCodecContext(CodecContext):
 
         def __set__(self, unsigned int value):
             self.ptr.width = value
-            self._build_format()
 
     property height:
         def __get__(self):
@@ -92,16 +113,15 @@ cdef class VideoCodecContext(CodecContext):
 
         def __set__(self, unsigned int value):
             self.ptr.height = value
-            self._build_format()
 
     # TODO: Replace with `format`.
     property pix_fmt:
         def __get__(self):
-            return self._format.name
+            if self.format != None:
+                return self.format.name
 
         def __set__(self, value):
             self.ptr.pix_fmt = lib.av_get_pix_fmt(value)
-            self._build_format()
 
     property framerate:
         """
diff --git a/include/libavcodec/avcodec.pxd b/include/libavcodec/avcodec.pxd
index 92d860d650aea9a4bc885642448570c79b63fda4..0490c7a56ff533e5a27a218dec9f955a49315786 100644
--- a/include/libavcodec/avcodec.pxd
+++ b/include/libavcodec/avcodec.pxd
@@ -202,6 +202,7 @@ cdef extern from "libavcodec/avcodec.h" nogil:
         int coded_height
 
         AVPixelFormat pix_fmt
+        AVPixelFormat get_format(AVCodecContext *ctx, const AVPixelFormat *fmt)
         AVRational sample_aspect_ratio
         int gop_size # The number of pictures in a group of pictures, or 0 for intra_only.
         int max_b_frames
@@ -245,6 +246,8 @@ cdef extern from "libavcodec/avcodec.h" nogil:
     cdef AVCodecDescriptor* avcodec_descriptor_get (AVCodecID id)
     cdef AVCodecDescriptor* avcodec_descriptor_get_by_name (char *name)
 
+    cdef AVPixelFormat avcodec_default_get_format(AVCodecContext *ctx, const AVPixelFormat *fmt)
+
     cdef char* avcodec_get_name(AVCodecID id)
 
     cdef char* av_get_profile_name(AVCodec *codec, int profile)
diff --git a/tests/test_codec_context.py b/tests/test_codec_context.py
index b213c04750e5e135135c40213b8101d92173fcee..a6d0156861a4cc4712add924374c18776658a9c8 100644
--- a/tests/test_codec_context.py
+++ b/tests/test_codec_context.py
@@ -51,6 +51,26 @@ class TestCodecContext(TestCase):
         # This one parses into many small packets.
         self._assert_parse('mpeg2video', fate_suite('mpeg2/mpeg2_field_encoding.ts'))
 
+    def test_format_override(self):
+        # Some decoders may override pix_fmt
+        ctx = Codec('gif', 'r').create()
+        ctx.pix_fmt = 'yuv420p'
+        ctx.width = 500
+        ctx.height = 500
+        ctx.open()
+        self.assertNotEqual(ctx.pix_fmt, 'yuv420p')
+
+    def test_format_not_set(self):
+        ctx = Codec('png', 'w').create()
+        self.assertEqual(ctx.format, None)
+        self.assertEqual(ctx.pix_fmt, None)
+        ctx.pix_fmt = 'bgra'
+        self.assertEqual(ctx.format.name, 'bgra')
+        self.assertEqual(ctx.pix_fmt, 'bgra')
+        ctx.pix_fmt = 'invalid'
+        self.assertEqual(ctx.format, None)
+        self.assertEqual(ctx.pix_fmt, None)
+
     def _assert_parse(self, codec_name, path):
 
         fh = av.open(path)