--- configure.ac	2012-03-29 21:44:28.000000000 +0200
+++ configure.ac	2013-04-23 17:11:05.000000000 +0200
@@ -9,7 +9,8 @@
 
 USER_CFLAGS=$CFLAGS
 
-AM_CONFIG_HEADER(config.h)
+dnl AM_CONFIG_HEADER(config.h)
+AC_CONFIG_HEADERS(config.h)
 
 AC_CANONICAL_HOST
 AM_MAINTAINER_MODE
@@ -39,7 +40,7 @@
 dnl Libquicktime codec API version
 dnl 
 
-LQT_CODEC_API_VERSION="12"
+LQT_CODEC_API_VERSION="13"
 
 AH_TEMPLATE([HAVE_GPL], [Enable GPL code])
 AH_TEMPLATE([LQT_CODEC_API_VERSION],
--- include/colorspace_macros.h	2011-12-08 18:46:10.000000000 +0100
+++ include/colorspace_macros.h	2012-11-08 13:53:45.000000000 +0100
@@ -372,12 +372,12 @@
 /* YUV (10 bit) -> 8 */
 
 #define YUV_10_TO_RGB_24(y,u,v,r,g,b) \
-  i_tmp=(yj_16_to_rgb * (y-0x40) + vj_16_to_r * (v-0x200))>>18;        \
-  r = RECLIP_8(i_tmp);\
-  i_tmp=(yj_16_to_rgb * (y-0x40) + uj_16_to_g * (u-0x200)+ vj_16_to_g * (v-0x200))>>18; \
-  g = RECLIP_8(i_tmp);\
-  i_tmp=(yj_16_to_rgb * (y-0x40) + uj_16_to_b * (u-0x200))>>18; \
-  b = RECLIP_8(i_tmp);
+   i_tmp=(y_16_to_rgb * (y-0x40) + v_16_to_r * (v-0x200))>>18;        \
+   r = RECLIP_8(i_tmp);\
+   i_tmp=(y_16_to_rgb * (y-0x40) + u_16_to_g * (u-0x200)+ v_16_to_g * (v-0x200))>>18; \
+   g = RECLIP_8(i_tmp);\
+   i_tmp=(y_16_to_rgb * (y-0x40) + u_16_to_b * (u-0x200))>>18; \
+   b = RECLIP_8(i_tmp);
 
 #define YUVJ_10_TO_RGB_24(y,u,v,r,g,b) \
   i_tmp=(yj_16_to_rgb * y + vj_16_to_r * (v-0x200))>>18;        \
--- include/lqt_funcprotos.h	2012-02-25 20:46:55.000000000 +0100
+++ include/lqt_funcprotos.h	2012-11-19 17:59:29.000000000 +0100
@@ -1015,6 +1015,14 @@
 void quicktime_read_stss(quicktime_t *file, quicktime_stss_t *stss);
 void quicktime_write_stss(quicktime_t *file, quicktime_stss_t *stss);
 
+/* stps.c */
+
+void quicktime_stps_init(quicktime_stps_t *stps);
+void quicktime_stps_delete(quicktime_stps_t *stps);
+void quicktime_stps_dump(quicktime_stps_t *stps);
+void quicktime_read_stps(quicktime_t *file, quicktime_stps_t *stps);
+void quicktime_write_stps(quicktime_t *file, quicktime_stps_t *stps);
+
 /* stsz.c */
 
 void quicktime_stsz_init(quicktime_stsz_t *stsz);
@@ -1033,6 +1041,14 @@
                            long sample_size);
 void quicktime_stsz_init_timecode(quicktime_stsz_t *stsz);
 
+/* sdtp.c */
+
+void quicktime_sdtp_init(quicktime_sdtp_t *sdtp);
+void quicktime_sdtp_delete(quicktime_sdtp_t *sdtp);
+void quicktime_sdtp_dump(quicktime_sdtp_t *sdtp);
+void quicktime_read_sdtp(quicktime_t *file, quicktime_sdtp_t *sdtp, long num_entries);
+void quicktime_write_sdtp(quicktime_t *file, quicktime_sdtp_t *sdtp);
+
 /* stts.c */
 
 void quicktime_stts_init(quicktime_stts_t *stts);
@@ -1462,7 +1478,8 @@
 int quicktime_codecs_flush(quicktime_t *file);
 
 LQT_EXTERN void lqt_write_frame_header(quicktime_t * file, int track,
-                                       int pic_num1, int64_t pic_pts, int keyframe);
+                                       int pic_num1, int64_t pic_pts,
+                                       enum LqtKeyFrame keyframe);
 
 LQT_EXTERN void lqt_write_frame_footer(quicktime_t * file, int track);
 
@@ -1480,3 +1497,9 @@
 /* workarounds.c */
 
 int64_t quicktime_add3(int64_t a, int64_t b, int64_t c);
+
+
+/* bframe_detector.c */
+
+LQT_EXTERN void quicktime_init_bframe_detector(quicktime_bframe_detector* ctx, quicktime_video_map_t* vtrack);
+LQT_EXTERN int quicktime_is_bframe(quicktime_bframe_detector* ctx, int64_t frame);
--- include/quicktime/lqt.h	2012-02-25 20:46:56.000000000 +0100
+++ include/quicktime/lqt.h	2013-02-12 18:32:53.000000000 +0100
@@ -1056,6 +1056,7 @@
  *  \param file A quicktime handle
  *  \param row_pointers Frame (see \ref lqt_rows_alloc)
  *  \param track Track index (starting with 0)
+ *  \returns 0 on success and a non-zero value on failure.
  *
  * Decode one video frame and increment the interal frame pointer.
  * To get the presentation timestamp for this frame, call
--- include/quicktime/qtprivate.h	2012-02-25 20:46:56.000000000 +0100
+++ include/quicktime/qtprivate.h	2012-11-19 17:59:29.000000000 +0100
@@ -592,6 +592,20 @@
   quicktime_stss_table_t *table;
   } quicktime_stss_t;
 
+/* partial sync sample */
+typedef struct
+  {
+  long sample;
+  } quicktime_stps_table_t;
+
+typedef struct
+  {
+  int version;
+  long flags;
+  long total_entries;
+  long entries_allocated;
+  quicktime_stps_table_t *table;
+  } quicktime_stps_t;
 
 /* sample to chunk */
 typedef struct
@@ -629,6 +643,15 @@
   quicktime_stsz_table_t *table;
   } quicktime_stsz_t;
 
+/* sample dependency table */
+typedef struct
+  {
+  int version;
+  long flags;
+  long total_entries;
+  long entries_allocated;
+  uint8_t *table;
+  } quicktime_sdtp_t;
 
 /* chunk offset */
 typedef struct
@@ -656,8 +679,10 @@
   quicktime_stsd_t stsd;
   quicktime_stts_t stts;
   quicktime_stss_t stss;
+  quicktime_stps_t stps;
   quicktime_stsc_t stsc;
   quicktime_stsz_t stsz;
+  quicktime_sdtp_t sdtp;
   quicktime_stco_t stco;
   quicktime_ctts_t ctts;
   int has_ctts;
@@ -1357,6 +1382,14 @@
   
   } quicktime_audio_map_t;
 
+
+enum LqtKeyFrame {
+    LQT_NO_KEY_FRAME      = 0,
+    LQT_FULL_KEY_FRAME    = 1,
+    LQT_PARTIAL_KEY_FRAME = 2 /* Corresponds to an I-frame in an open GOP. */
+};
+
+
 typedef struct
   {
   quicktime_trak_t *track;
@@ -1421,9 +1454,12 @@
 
   /* For encoding */
   quicktime_atom_t chunk_atom;
-  int keyframe;
+  enum LqtKeyFrame keyframe;
 
   lqt_compression_info_t ci;
+
+  /* 1 if encoding, 0 if decoding. */
+  int do_encode;
   
   } quicktime_video_map_t;
 
@@ -1680,4 +1716,13 @@
 
   };
 
+
+typedef struct
+  {
+  int64_t frame;
+  long ctts_entry_idx;
+  long sample_within_entry;
+  quicktime_ctts_t *ctts;
+  } quicktime_bframe_detector;
+
 #endif
--- include/quicktime/quicktime.h	2011-01-17 18:24:15.000000000 +0100
+++ include/quicktime/quicktime.h	2012-11-19 17:59:29.000000000 +0100
@@ -1098,10 +1098,15 @@
 
 /* One keyframe table for each track */
 long quicktime_get_keyframe_before(quicktime_t *file, long frame, int track);
+long quicktime_get_partial_keyframe_before(quicktime_t *file, long frame, int track);
 void quicktime_insert_keyframe(quicktime_t *file, long frame, int track);
+void quicktime_insert_partial_keyframe(quicktime_t *file, long frame, int track);
 /* Track has keyframes */
 int quicktime_has_keyframes(quicktime_t *file, int track);
 
+/* Sample dependencies for long-GOP formats. */
+void quicktime_insert_sdtp_entry(quicktime_t *file, long frame, int track, uint8_t flags);
+
 /* ===================== Access to built in codecs follows. */
 
 /* If the codec for this track is supported in the library return 1. */
--- plugins/audiocodec/pcm.c	2011-08-22 14:09:48.000000000 +0200
+++ plugins/audiocodec/pcm.c	2013-05-21 15:42:20.000000000 +0200
@@ -1053,7 +1053,7 @@
     {
     case 8:
       atrack->block_align = atrack->channels;
-      atrack->sample_format = LQT_SAMPLE_UINT8;
+      atrack->sample_format = LQT_SAMPLE_INT8;
       codec->encode = encode_8;
       codec->decode = decode_8;
       break;
--- plugins/faac/faac.c	2011-01-07 15:40:46.000000000 +0100
+++ plugins/faac/faac.c	2013-04-29 10:30:54.000000000 +0200
@@ -52,6 +52,7 @@
   int bitrate;
   int quality;
   int object_type;
+  int priming_delay;  
   } quicktime_faac_codec_t;
 
 
@@ -80,7 +81,7 @@
 
   imax = codec->sample_buffer_size * track_map->channels;
   
-  if(!num_samples && (codec->encoder_delay < 0))
+  if(!num_samples && (codec->encoder_delay < -FAAC_PRIMING_DELAY))
     return 0;
   
   for(i = 0; i < imax; i++)
@@ -116,10 +117,10 @@
   lqt_start_audio_vbr_frame(file, track);
   result = !quicktime_write_data(file, codec->chunk_buffer,
                                  bytes_encoded);
-  if(codec->encoder_delay < 0)
+  if(codec->encoder_delay < -FAAC_PRIMING_DELAY)
     {
     lqt_finish_audio_vbr_frame(file, track, codec->samples_per_frame +
-                               codec->encoder_delay);
+                               codec->encoder_delay + FAAC_PRIMING_DELAY);
     }
   else
     lqt_finish_audio_vbr_frame(file, track, codec->samples_per_frame);
@@ -205,6 +206,7 @@
   {
   int samples_read;
   int samples_to_copy;
+  int priming_delay = 0;
   
   faacEncConfigurationPtr enc_config;
   unsigned long input_samples;
@@ -255,6 +257,9 @@
 #endif
     codec->chunk_buffer_size = output_bytes;
     codec->chunk_buffer = malloc(codec->chunk_buffer_size);
+
+    if(codec->priming_delay > FAAC_PRIMING_DELAY)
+      priming_delay = codec->priming_delay - FAAC_PRIMING_DELAY;
     
     codec->initialized = 1;
 
@@ -276,19 +281,37 @@
   
   while(samples_read < samples)
     {
+    /* Add priming delay */
+    if(priming_delay >= codec->samples_per_frame)
+      {
+	memset(codec->sample_buffer, 0,
+	       codec->samples_per_frame * track_map->channels * sizeof(float));
+	codec->sample_buffer_size = codec->samples_per_frame;
+	priming_delay -= codec->samples_per_frame;
+      }
+    else if(priming_delay > 0)
+      {
+	memset(codec->sample_buffer, 0,
+	       priming_delay * track_map->channels * sizeof(float));
+	codec->sample_buffer_size = priming_delay;
+	priming_delay = 0;
+      }
     /* Put samples into sample buffer */
     
     samples_to_copy = codec->samples_per_frame - codec->sample_buffer_size;
     if(samples_read + samples_to_copy > samples)
       samples_to_copy = samples - samples_read;
 
-    memcpy(codec->sample_buffer +
-           track_map->channels * codec->sample_buffer_size,
-           input + samples_read * track_map->channels,
-           samples_to_copy * track_map->channels * sizeof(float));
-    
-    codec->sample_buffer_size += samples_to_copy;
-    samples_read += samples_to_copy;
+    if(samples_to_copy > 0)
+      {
+	memcpy(codec->sample_buffer +
+	       track_map->channels * codec->sample_buffer_size,
+	       input + samples_read * track_map->channels,
+	       samples_to_copy * track_map->channels * sizeof(float));
+	
+	codec->sample_buffer_size += samples_to_copy;
+	samples_read += samples_to_copy;
+      }
     
     /* Encode one frame, possibly starting a new audio chunk */
     if(codec->sample_buffer_size == codec->samples_per_frame)
@@ -312,7 +335,7 @@
   {
   quicktime_audio_map_t *track_map = &file->atracks[track];
   quicktime_faac_codec_t *codec = track_map->codec->priv;
-    
+
   if(!strcasecmp(key, "faac_bitrate"))
     codec->bitrate = *(int*)value;
   else if(!strcasecmp(key, "faac_quality"))
@@ -328,6 +351,8 @@
     else if(!strcmp((char*)value, "LTP"))
       codec->object_type = LTP;
     }
+  else if(!strcasecmp(key, "faac_priming_delay"))
+    codec->priming_delay = *(int*)value;
   return 0;
   }
 
@@ -404,6 +429,7 @@
   
   codec->bitrate = 0;
   codec->quality = 100;
+  codec->priming_delay = 2112;
 
   if(!atrack)
     return;
--- plugins/faac/lqt_faac.c	2011-01-07 15:40:46.000000000 +0100
+++ plugins/faac/lqt_faac.c	2013-04-29 10:30:54.000000000 +0200
@@ -39,7 +39,7 @@
       .val_default = { .val_int = 0 }
     },
     {
-      .name =        "quality",
+      .name =        "faac_quality",
       .real_name =   TRS("VBR Quality"),
       .type =        LQT_PARAMETER_INT,
       .val_min =     { .val_int = 10 },
@@ -47,7 +47,7 @@
       .val_default = { .val_int = 100 },
     },
     {
-      .name        = "object_type",
+      .name        = "faac_object_type",
       .real_name   = TRS("Object type"),
       .type        = LQT_PARAMETER_STRINGLIST,
       .val_default = { .val_string = "Low" },
@@ -57,6 +57,13 @@
                                        TRS("LTP"),
                                        (char*)0 },
     },
+    {
+      .name =        "faac_priming_delay",
+      .real_name =   TRS("Priming delay (samples)"),
+      .type =        LQT_PARAMETER_INT,
+      .val_min =     { .val_int = FAAC_PRIMING_DELAY },
+      .val_default = { .val_int = 2112 },
+    },
     { /* End of parameters */ }
   };
 
--- plugins/faac/qtfaac.h	2011-01-07 15:40:46.000000000 +0100
+++ plugins/faac/qtfaac.h	2013-04-29 10:30:54.000000000 +0200
@@ -22,6 +22,8 @@
  Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 *******************************************************************************/ 
 
+#define FAAC_PRIMING_DELAY 1024
+
 void quicktime_init_codec_faac(quicktime_codec_t * codec,
                                quicktime_audio_map_t *atrack,
                                quicktime_video_map_t *vtrack);
--- plugins/ffmpeg/audio.c	2012-03-29 21:44:28.000000000 +0200
+++ plugins/ffmpeg/audio.c	2013-04-21 23:54:58.000000000 +0200
@@ -45,6 +45,11 @@
 #define ENCODE_AUDIO 1
 #endif
 
+#ifndef AVCODEC_MAX_AUDIO_FRAME_SIZE
+/* from libavcodec/avcodec.h dated Dec 23 2012 */
+#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio
+#endif
+
 /* The following code was ported from gmerlin_avdecoder (http://gmerlin.sourceforge.net) */
 
 /* MPEG Audio header parsing code */
--- plugins/ffmpeg/lqt_ffmpeg.c	2012-02-15 20:48:30.000000000 +0100
+++ plugins/ffmpeg/lqt_ffmpeg.c	2013-06-07 16:36:20.000000000 +0200
@@ -53,6 +53,10 @@
 #define CODEC_TYPE_NB         AVMEDIA_TYPE_NB
 #endif
 
+#if LIBAVCODEC_VERSION_INT > ((53<<16)|(17<<8)|0)
+#define HAVE_PRORES_SUPPORT
+#endif
+
   
 #define ENCODE_PARAM_AUDIO \
   { \
@@ -198,10 +202,22 @@
     .val_default = { .val_int = 1 }  \
   }
 
+#define ENCODE_PARAM_PRORES                                             \
+  {                                                                     \
+    .name = "prores_profile",                                           \
+    .real_name = TRS("ProRes profile"),                                 \
+    .type = LQT_PARAMETER_STRINGLIST,                                   \
+    .val_default = { .val_string =  "Standard" },                       \
+    .stringlist_options = (char *[]){ "HQ", "Standard",  "LT", "Proxy", \
+                                      (char *)0 }                       \
+  }
+
 #define DECODE_PARAM_AUDIO
 
 #define DECODE_PARAM_VIDEO \
-  PARAM_FLAG_GRAY
+  PARAM_FLAG_GRAY,         \
+  PARAM_THREAD_COUNT
+
 
 static lqt_parameter_info_static_t encode_parameters_mpeg4[] = {
   ENCODE_PARAM_VIDEO_FRAMETYPES_IPB,
@@ -292,10 +308,27 @@
 };
 
 static lqt_parameter_info_static_t encode_parameters_imx[] = {
+  PARAM_THREAD_COUNT,
   ENCODE_PARAM_IMX,
   { /* End of parameters */ }
 };
 
+static lqt_parameter_info_static_t encode_parameters_dnxhd[] = {
+  PARAM_THREAD_COUNT,
+  { /* End of parameters */ }
+};
+
+static lqt_parameter_info_static_t encode_parameters_xdcam_hd422[] = {
+  PARAM_THREAD_COUNT,
+  { /* End of parameters */ }
+};
+
+static lqt_parameter_info_static_t encode_parameters_prores[] = {
+  PARAM_THREAD_COUNT,
+  ENCODE_PARAM_PRORES,
+  { /* End of parameters */ }
+};
+
 
 static lqt_parameter_info_static_t encode_parameters_audio[] = {
   ENCODE_PARAM_AUDIO,
@@ -684,6 +717,7 @@
       .index = -1,
       .encoder = NULL,
       .decoder = NULL,
+      .decode_parameters = decode_parameters_video,
       .short_name = "rle",
       .name = TRS("FFMPEG RLE"),
       .fourccs = { "rle ", (char *)0 },
@@ -697,6 +731,7 @@
       .index = -1,
       .encoder = NULL,
       .decoder = NULL,
+      .decode_parameters = decode_parameters_video,
       .short_name = "wrle",
       .name = TRS("FFMPEG Microsoft RLE"),
       .fourccs = { "WRLE", (char *)0 },
@@ -806,6 +841,7 @@
       .encoder = NULL,
       .decoder = NULL,
       .decode_parameters = decode_parameters_video,
+      .encode_parameters = encode_parameters_dnxhd,
       .image_sizes = image_sizes_dnxhd,
       .short_name = "dnxhd",
       .name = TRS("FFMPEG dnxhd"),
@@ -826,12 +862,72 @@
       .image_sizes = image_sizes_imx,
       .short_name = "imx",
       .name = TRS("FFMPEG IMX"),
-      .fourccs = { "mx3p", "mx3n", "mx4p", "mx4n", "mx5p", "mx5n", (char *)0 },
+      .fourccs = { "mx3p", "mx3n", "mx4p", "mx4n", "mx5p", "mx5n", "AVmp", (char *)0 },
       .wav_ids = { LQT_WAV_ID_NONE },
       .compatibility_flags = LQT_FILE_QT_OLD | LQT_FILE_QT,
       .do_encode = 1,
       .compression_id = LQT_COMPRESSION_D10
     },
+    {
+      .id = CODEC_ID_MPEG2VIDEO,
+      .index = -1,
+      .encoder = NULL,
+      .decoder = NULL,
+      .decode_parameters = decode_parameters_video,
+      .short_name = "xdcam_hd",
+      .name = TRS("FFMPEG XDCAM HD"),
+      .fourccs = {
+        "xdv1", "xdv2", "xdv3", "xdv4", "xdv5", "xdv6", "xdv7", "xdv8",
+        "xdv9", "xdva", (char *)0 },
+      .wav_ids = { LQT_WAV_ID_NONE },
+      .compatibility_flags = LQT_FILE_QT
+    },
+    {
+      .id = CODEC_ID_MPEG2VIDEO,
+      .index = -1,
+      .encoder = NULL,
+      .decoder = NULL,
+      .decode_parameters = decode_parameters_video,
+      .short_name = "xdcam_ex",
+      .name = TRS("FFMPEG XDCAM EX"),
+      .fourccs = { "xdvb", "xdvc", "xdvd", "xdve", "xdvf", (char *)0 },
+      .wav_ids = { LQT_WAV_ID_NONE },
+      .compatibility_flags = LQT_FILE_QT
+    },
+    {
+      .id = CODEC_ID_MPEG2VIDEO,
+      .index = -1,
+      .encoder = NULL,
+      .decoder = NULL,
+      .decode_parameters = decode_parameters_video,
+      .encode_parameters = encode_parameters_xdcam_hd422,
+      .short_name = "xdcam_hd422",
+      .name = TRS("FFMPEG XDCAM HD422"),
+      .fourccs = {
+        "xd54", "xd55", "xd59", "xd5a", "xd5b", "xd5c", "xd5d", "xd5e", "xd5f",
+        (char *)0 },
+      .wav_ids = { LQT_WAV_ID_NONE },
+      .compatibility_flags = LQT_FILE_QT,
+      .do_encode = 1,
+      .encoding_colormodels = (int[]){ BC_YUV422P, LQT_COLORMODEL_NONE }
+    },
+#ifdef HAVE_PRORES_SUPPORT
+    {
+      .id = CODEC_ID_PRORES,
+      .index = -1,
+      .encoder = NULL,
+      .decoder = NULL,
+      .decode_parameters = decode_parameters_video,
+      .encode_parameters = encode_parameters_prores,
+      .short_name = "prores",
+      .name = TRS("FFMPEG ProRes"),
+      .fourccs = { "apch", "apcn", "apcs", "apco", (char *)0 },
+      .wav_ids = { LQT_WAV_ID_NONE },
+      .compatibility_flags = LQT_FILE_QT,
+      .do_encode = 1,
+      .encoding_colormodels = (int[]){ BC_YUV422P10, LQT_COLORMODEL_NONE }
+    },
+#endif
 };
 
 /* Audio */
@@ -955,7 +1051,21 @@
   for(i = 0; i < NUMMAPS_V; i++)
     {
     if(codecidmap_v[i].do_encode)
-      codecidmap_v[i].encoder = avcodec_find_encoder(codecidmap_v[i].id);
+      {
+#ifdef HAVE_PRORES_SUPPORT
+      // FFMpeg has 2 different ProRes encoders, so try the better one first.
+      if(codecidmap_v[i].id == CODEC_ID_PRORES)
+        {
+        // In newer versions it's called prores_ks. It used to be called prores_kostya
+        codecidmap_v[i].encoder = avcodec_find_encoder_by_name("prores_ks");
+        if(!codecidmap_v[i].encoder)
+          codecidmap_v[i].encoder = avcodec_find_encoder_by_name("prores_kostya");
+        }
+
+      if(!codecidmap_v[i].encoder)
+#endif
+        codecidmap_v[i].encoder = avcodec_find_encoder(codecidmap_v[i].id);
+      }
     codecidmap_v[i].decoder = avcodec_find_decoder(codecidmap_v[i].id);
 
     if(codecidmap_v[i].encoder || codecidmap_v[i].decoder)
--- plugins/ffmpeg/params.c	2012-03-07 15:10:41.000000000 +0100
+++ plugins/ffmpeg/params.c	2013-05-07 11:18:51.000000000 +0200
@@ -101,6 +101,17 @@
     }                                           \
   }
 
+#define PARAM_DICT_INT(name, dict_name)             \
+  {                                                 \
+  if(!strcasecmp(name, key))                        \
+    {                                               \
+    char buf[128];                                  \
+    snprintf(buf, sizeof(buf), "%d", *(int*)value); \
+    av_dict_set(options, dict_name, buf, 0);        \
+    found = 1;                                      \
+    }                                               \
+  }
+
 #define PARAM_DICT_FLAG(name, dict_name)        \
   {                                             \
   if(!strcasecmp(name, key))                    \
@@ -202,8 +213,15 @@
   PARAM_INT("ff_max_b_frames",max_b_frames);
   PARAM_FLOAT("ff_b_quant_factor",b_quant_factor);
   PARAM_INT("ff_b_frame_strategy",b_frame_strategy);
+
+#if LIBAVCODEC_VERSION_MAJOR >= 55
+  PARAM_DICT_INT("ff_luma_elim_threshold","luma_elim_threshold");
+  PARAM_DICT_INT("ff_chroma_elim_threshold","chroma_elim_threshold");
+#else
   PARAM_INT("ff_luma_elim_threshold",luma_elim_threshold);
   PARAM_INT("ff_chroma_elim_threshold",chroma_elim_threshold);
+#endif
+
   PARAM_INT("ff_strict_std_compliance",strict_std_compliance);
   PARAM_QP2LAMBDA("ff_b_quant_offset",b_quant_offset);
   PARAM_INT("ff_rc_min_rate",rc_min_rate);
@@ -241,8 +259,15 @@
   PARAM_QP2LAMBDA("ff_lmax", lmax);
   PARAM_INT("ff_noise_reduction",noise_reduction);
   PARAM_INT_SCALE("ff_rc_initial_buffer_occupancy",rc_initial_buffer_occupancy,1000);
+
+#if LIBAVCODEC_VERSION_MAJOR >= 55
+  PARAM_DICT_INT("ff_inter_threshold","inter_threshold");
+  PARAM_DICT_INT("ff_quantizer_noise_shaping","quantizer_noise_shaping");
+#else
   PARAM_INT("ff_inter_threshold",inter_threshold);
   PARAM_INT("ff_quantizer_noise_shaping",quantizer_noise_shaping);
+#endif
+
   PARAM_INT("ff_thread_count",thread_count);
   PARAM_INT("ff_me_threshold",me_threshold);
   PARAM_INT("ff_mb_threshold",mb_threshold);
@@ -272,8 +297,16 @@
   PARAM_FLAG("ff_flag_bitexact",CODEC_FLAG_BITEXACT);
   PARAM_FLAG("ff_flag_ac_pred",CODEC_FLAG_AC_PRED);
   //  PARAM_FLAG("ff_flag_h263p_umv",CODEC_FLAG_H263P_UMV); // Unused
+
+#if LIBAVCODEC_VERSION_MAJOR >= 55
+  PARAM_DICT_FLAG("ff_flag_cbp_rd","cbp_rd");
+  PARAM_DICT_FLAG("ff_flag_qp_rd","qp_rd");
+  PARAM_DICT_FLAG("ff_flag2_strict_gop","strict_gop");
+#else
   PARAM_FLAG("ff_flag_cbp_rd",CODEC_FLAG_CBP_RD);
   PARAM_FLAG("ff_flag_qp_rd",CODEC_FLAG_QP_RD);
+  PARAM_FLAG2("ff_flag2_strict_gop",CODEC_FLAG2_STRICT_GOP);
+#endif
 
 #if LIBAVCODEC_VERSION_MAJOR >= 54
   PARAM_DICT_FLAG("ff_flag_h263p_aiv", "aiv");
@@ -288,7 +321,6 @@
   PARAM_FLAG("ff_flag_loop_filter",CODEC_FLAG_LOOP_FILTER);
   PARAM_FLAG("ff_flag_closed_gop",CODEC_FLAG_CLOSED_GOP);
   PARAM_FLAG2("ff_flag2_fast",CODEC_FLAG2_FAST);
-  PARAM_FLAG2("ff_flag2_strict_gop",CODEC_FLAG2_STRICT_GOP);
   PARAM_ENUM("ff_coder_type",coder_type,coder_type);
   
   }
--- plugins/ffmpeg/video.c	2012-02-25 20:46:56.000000000 +0100
+++ plugins/ffmpeg/video.c	2013-06-05 17:10:48.000000000 +0200
@@ -43,12 +43,33 @@
 #define PIX_FMT_YUV422P10_OR_DUMMY -1234
 #endif
 
+#if LIBAVCODEC_VERSION_INT > ((53<<16)|(17<<8)|0)
+#define HAVE_PRORES_SUPPORT
+#endif
+
 #if LIBAVCODEC_VERSION_INT >= ((54<<16)|(1<<8)|0)
 #define ENCODE_VIDEO2 1
 #else
 #define ENCODE_VIDEO 1
 #endif
 
+static const struct
+{
+    const char* fourcc;
+
+    /* There are two different ProRes encoders in FFMpeg. One of them
+       only accepts numeric profile values, while the other one also
+       accepts profile names. Fortunately, they do agree on numeric values. */
+    const char* ffmpeg_profile;
+
+    const char* lqt_name;
+} lqt_prores_profiles[] = {
+    { "apco", "0", "Proxy" },
+    { "apcs", "1", "LT" },
+    { "apcn", "2", "Standard" },
+    { "apch", "3", "HQ" }
+};
+
 /* We keep the numeric values the same as in the ACLR atom.
    The interpretation of values is based on trial and error. */
 enum AvidYuvRange
@@ -95,7 +116,9 @@
   enum PixelFormat reinterpret_pix_fmt;
   
   int is_imx;
+  int is_xdcam_hd422;
   int y_offset;
+  int prores_profile; // Index into lqt_prores_profiles, for encoding only.
 
 #if LIBAVCODEC_VERSION_MAJOR < 54
   AVPaletteControl palette;
@@ -129,6 +152,12 @@
 
   /* Stuff for compressed H.264 reading */
   int nal_size_length;
+
+  quicktime_bframe_detector bframe_detector;
+
+  /* lqt_pts = ffmpeg_pts * pts_factor */
+  int encoding_pts_factor;
+
   } quicktime_ffmpeg_video_codec_t;
 
 /* ffmpeg <-> libquicktime colormodels */
@@ -291,6 +320,46 @@
   *p += 4;
   }
 
+static uint8_t generate_sdtp_flags_mpeg2(long frame, const AVCodecContext* avctx)
+  {
+  unsigned flags = 0;
+
+  switch(avctx->coded_frame->pict_type)
+    {
+    case AV_PICTURE_TYPE_I:
+      flags |= 0x20; // doesnt_depend_on_other_samples
+      if(avctx->gop_size > 1)
+        flags |= 0x04; // other_samples_depend_on_this_one
+      if(avctx->max_b_frames > 0)
+        flags |= 0x40; // earlier_dps_allowed
+      break;
+    case AV_PICTURE_TYPE_P:
+      flags |= 0x10; // sample_depends_on_others
+      if(avctx->max_b_frames > 0)
+        flags |= 0x40|0x04; // earlier_dps_allowed|other_samples_depend_on_this_one
+      break;
+    case AV_PICTURE_TYPE_B:
+      flags |= 0x10|0x08; // sample_depends_on_others|no_other_samples_depend_on_this_one
+      break;
+    default:;
+    }
+
+  return (uint8_t)flags;
+  }
+
+static void maybe_add_sdtp_entry(quicktime_t* file, long sample, int track)
+  {
+  quicktime_video_map_t *vtrack = &file->vtracks[track];
+  quicktime_ffmpeg_video_codec_t *codec = vtrack->codec->priv;
+
+  if (codec->encoder->id == CODEC_ID_MPEG2VIDEO && codec->avctx->gop_size > 1)
+    {
+    uint8_t flags = generate_sdtp_flags_mpeg2(sample, codec->avctx);
+    quicktime_insert_sdtp_entry(file, sample, track, flags);
+    }
+  }
+
+
 #ifndef HAVE_LIBSWSCALE
 static void fill_avpicture(AVPicture * ret, unsigned char ** rows,
                            int lqt_colormodel,
@@ -400,7 +469,17 @@
   codec->reinterpret_pix_fmt = codec->avctx->pix_fmt;
 
   /* First we try codec-specific colormodel matching. */
-  if(codec->decoder->id == CODEC_ID_DNXHD)
+  if(codec->is_imx && quicktime_match_32(vtrack->track->mdia.minf.stbl.stsd.table[0].format, "AVmp"))
+    {
+     if (lqt_ffmpeg_get_avid_yuv_range(vtrack->track) == AVID_FULL_YUV_RANGE)
+       {
+       vtrack->stream_cmodel = BC_YUVJ422P;
+       codec->reinterpret_pix_fmt = PIX_FMT_YUVJ422P;
+       *exact = 1;
+       return;
+       }
+    }
+  else if(codec->decoder->id == CODEC_ID_DNXHD)
     {
     /* FFMpeg supports PIX_FMT_YUV422P and PIX_FMT_YUV422P10 for DNxHD, which
        we sometimes interpret as PIX_FMT_YUVJ422P and PIX_FMT_YUVJ422P10. */
@@ -662,12 +741,13 @@
         codec->y_offset = codec->avctx->height - trak->tkhd.track_height;
         vtrack->height_extension = 0;
     } else {
+        int stsd_height = trak->mdia.minf.stbl.stsd.table[0].height;
         codec->y_offset = 0;
-        if (vtrack->height_extension == codec->avctx->height - trak->tkhd.track_height) {
+        if (vtrack->height_extension == codec->avctx->height - stsd_height) {
             return;
         }
 
-        vtrack->height_extension = codec->avctx->height - trak->tkhd.track_height;
+        vtrack->height_extension = codec->avctx->height - stsd_height;
 
         /* Now we need a larger temp_frame */
         if (vtrack->temp_frame) {
@@ -883,8 +963,9 @@
                                &got_pic,
                                &codec->pkt) < 0)
         {
-        lqt_log(file, LQT_LOG_ERROR, LOG_DOMAIN, "Skipping corrupted frame");
-        continue;
+        lqt_log(file, LQT_LOG_WARNING, LOG_DOMAIN, "Broken frame encountered");
+        codec->decoding_delay--;
+        return 1;
         }
 
 #if LIBAVCODEC_VERSION_MAJOR >= 54
@@ -907,15 +988,16 @@
                               codec->buffer,
                               buffer_size) < 0)
         {
-        lqt_log(file, LQT_LOG_ERROR, LOG_DOMAIN, "Skipping corrupted frame");
-        continue;
+        lqt_log(file, LQT_LOG_WARNING, LOG_DOMAIN, "Broken frame encountered");
+        codec->decoding_delay--;
+        return 1;
         }
 #endif      
       if(got_pic)
         codec->decoding_delay--;
       
       if((buffer_size <= 0) && !got_pic)
-        return 0;
+        return 1;
       }
     }
   
@@ -972,9 +1054,11 @@
 
       vtrack->chroma_placement = LQT_CHROMA_PLACEMENT_MPEG2;
       vtrack->ci.id = LQT_COMPRESSION_D10;
-      vtrack->ci.bitrate = 
-        (trak->mdia.minf.stbl.stsd.table[0].format[2] - '0') *
-        10000000;
+      if (quicktime_match_32(trak->mdia.minf.stbl.stsd.table[0].format, "AVmp"))
+        vtrack->ci.bitrate = 50000000;
+      else
+        vtrack->ci.bitrate =
+          (trak->mdia.minf.stbl.stsd.table[0].format[2] - '0') * 10000000;
       }
     
     if(codec->avctx->sample_aspect_ratio.num)
@@ -1030,58 +1114,133 @@
   return result;
   }
 
+static int64_t bitstream_i_frame_to_display_frame(int64_t bitstream_i_frame, quicktime_bframe_detector* bframe_detector)
+  {
+  if (!bframe_detector)
+    return bitstream_i_frame; // Assuming closed GOP.
+  else
+    { // This branch can also handle P-frames, though we aren't relying on that.
+    int num_following_b_frames = 0;
+    while (quicktime_is_bframe(bframe_detector, bitstream_i_frame + num_following_b_frames + 1) == 1)
+      {
+      num_following_b_frames++;
+      }
+    return bitstream_i_frame + num_following_b_frames;
+    }
+  }
+
+static int64_t bitstream_b_frame_to_display_frame(int64_t bitstream_b_frame)
+  {
+  return bitstream_b_frame - 1;
+  }
+
+static int64_t get_bitstream_sync_frame(quicktime_t* file, int64_t display_frame, int track, quicktime_bframe_detector* bframe_detector)
+  {
+  int64_t full_sync_kf = quicktime_get_keyframe_before(file, display_frame, track);
+  int64_t partial_sync_kf = quicktime_get_partial_keyframe_before(file, display_frame, track);
+
+  while (partial_sync_kf > full_sync_kf && partial_sync_kf > 0)
+    {
+    if (bitstream_i_frame_to_display_frame(partial_sync_kf, bframe_detector) <= display_frame)
+      return partial_sync_kf;
+
+    partial_sync_kf = quicktime_get_partial_keyframe_before(file, partial_sync_kf - 1, track);
+    }
+
+  return full_sync_kf;
+  }
+
 static void resync_ffmpeg(quicktime_t *file, int track)
   {
-  int64_t keyframe, frame;
-  int buffer_size, got_pic;
   quicktime_video_map_t *vtrack = &file->vtracks[track];
   quicktime_ffmpeg_video_codec_t *codec = vtrack->codec->priv;
-  
+
+  const int64_t target_display_frame = vtrack->current_position; // Frame we are told to seek to.
+  int64_t bitstream_frame; // Current working frame in bitstream order.
+  int64_t buffer_size;
+  const int64_t total_frames = quicktime_video_length(file, track);
+  int decoded_frames_to_discard = 0;
+  int seen_non_b_frames = 0;
+  const int detect_bframes = vtrack->track->mdia.minf.stbl.has_ctts;
+  quicktime_bframe_detector* bframe_detector = detect_bframes ? &codec->bframe_detector : NULL;
+
   /* Forget about previously decoded frame */
   codec->have_frame = 0;
   codec->decoding_delay = 0;
-  
+
   /* Reset lavc */
   avcodec_flush_buffers(codec->avctx);
 
-  
-  if(quicktime_has_keyframes(file, track))
+  if(target_display_frame <= 0)
+    return;
+
+  if(!quicktime_has_keyframes(file, track))
+    return; // Assuming I-frame only stream.
+
+  bitstream_frame = get_bitstream_sync_frame(file, target_display_frame, track, bframe_detector);
+  decoded_frames_to_discard = target_display_frame - bitstream_i_frame_to_display_frame(bitstream_frame, bframe_detector);
+
+  for (;; bitstream_frame++)
     {
-    keyframe = quicktime_get_keyframe_before(file, vtrack->current_position, track);
+    int got_pic = 0;
 
-    frame = keyframe;
-    
-    while(frame < vtrack->current_position)
+    if (decoded_frames_to_discard <= 0) // Should not be < 0 unless the stream is broken.
       {
+      // We want vtrack->current_position + codec->decoding_delay == bitstream_frame
+      // when the next encoded frame is read.
+      codec->decoding_delay = bitstream_frame - vtrack->current_position;
+      break;
+      }
+
+    if (bitstream_frame < total_frames)
+      {
+      if (detect_bframes)
+        {
+        int is_bframe = quicktime_is_bframe(bframe_detector, bitstream_frame);
+        if (!is_bframe)
+          seen_non_b_frames++;
+
+        // Skip initial B-frames.
+        if (is_bframe && seen_non_b_frames < 2)
+          continue;
+
+        // Don't do IDCT where we don't have to.
+        if (is_bframe && bitstream_b_frame_to_display_frame(bitstream_frame) < target_display_frame)
+          codec->avctx->skip_idct = AVDISCARD_NONREF;
+        }
+
       buffer_size = lqt_read_video_frame(file, &codec->buffer,
                                          &codec->buffer_alloc,
-                                         frame + codec->decoding_delay,
-                                         NULL, track);
-      if(buffer_size > 0)
-        {
+                                         bitstream_frame, NULL, track);
+      }
+    else // if (bitstream_frame < total_frames)
+      {
+      // Feed an empty packet to the decoder to indicate end of stream,
+      // which will make it return the final decoded frames it still owes us.
+      buffer_size = 0;
+      }
+
 #if LIBAVCODEC_BUILD >= ((52<<16)+(26<<8)+0)
-        codec->pkt.data = codec->buffer;
-        codec->pkt.size = buffer_size;
-        avcodec_decode_video2(codec->avctx,
-                              codec->frame,
-                              &got_pic,
-                              &codec->pkt);
+    codec->pkt.data = codec->buffer;
+    codec->pkt.size = buffer_size;
+    avcodec_decode_video2(codec->avctx, codec->frame, &got_pic, &codec->pkt);
 #else
-        avcodec_decode_video(codec->avctx,
-                             codec->frame,
-                             &got_pic,
-                             codec->buffer,
-                             buffer_size);
+    avcodec_decode_video(codec->avctx, codec->frame, &got_pic, codec->buffer, buffer_size);
 #endif
-        if(!got_pic)
-          {
-          codec->decoding_delay++;
-          frame--;
-          }
-        }
-      frame++;
+
+    // Default value is necessary for normal decoding.
+    codec->avctx->skip_idct = AVDISCARD_DEFAULT;
+
+    if(got_pic)
+      decoded_frames_to_discard--;
+    else if (bitstream_frame >= total_frames)
+      {
+      // We've already fed an empty packet to the decoder, indicating
+      // no more data will follow, yet it didn't return any additional
+      // frames. At this point we give up and declare decoding failure.
+      break;
       }
-    }
+    } // for (;; bitstream_frame++)
   }
 
 static int set_pass_ffmpeg(quicktime_t *file, 
@@ -1128,6 +1287,82 @@
   
   }
 
+static const char* get_xdcam_hd422_fourcc(quicktime_t *file, int track, int height)
+  {
+  quicktime_video_map_t *vtrack = &file->vtracks[track];
+  int time_scale = lqt_video_time_scale(file, track);
+  int frame_duration = lqt_frame_duration(file, track, NULL);
+  int interlaced = vtrack->interlace_mode != LQT_INTERLACE_NONE;
+  int frame_rate_100; // Frame rate with 2 decimal places preserved, multiplied by 100.
+
+  if(frame_duration <= 0 || time_scale <= 0)
+    return NULL; // Sanity check.
+
+  frame_rate_100 = time_scale * 100 / frame_duration;
+
+  if(height == 720 && !interlaced) // Only progressive modes are supported for 720 lines.
+    {
+    if(interlaced)
+      {
+      lqt_log(file, LQT_LOG_WARNING, LOG_DOMAIN, "XDCAM HD422 supports 720p but not 720i");
+      return NULL;
+      }
+    else
+      {
+      switch(frame_rate_100)
+        {
+        case 2397:
+          return "xd54";
+        case 2500:
+          return "xd55";
+        case 6000:
+          return "xd59";
+        case 5000:
+          return "xd5a";
+        }
+      }
+    }
+  else if(height == 1080)
+    {
+    if(interlaced)
+      {
+      switch(frame_rate_100)
+        {
+        case 2500:
+          return "xd5c";
+        case 2997:
+          return "xd5b";
+        }
+      }
+    else // if(interlaced)
+      {
+      switch(frame_rate_100)
+        {
+        case 2397:
+          return "xd5d";
+        case 2500:
+          return "xd5e";
+        case 2997:
+          return "xd5f";
+        }
+      }
+    }
+  else if(height == 540)
+    {
+    lqt_log(file, LQT_LOG_WARNING, LOG_DOMAIN, "XDCAM HD422 540p is not supported");
+    return NULL;
+    }
+  else
+    {
+    lqt_log(file, LQT_LOG_WARNING, LOG_DOMAIN, "Frame height of %d is not supported by XDCAM HD422", height);
+    return NULL;
+    }
+
+  lqt_log(file, LQT_LOG_WARNING, LOG_DOMAIN, "Frame rate %d.%02d is not supported by XDCAM HD422, at least not for %d%c",
+          frame_rate_100 / 100, frame_rate_100 % 100, height, interlaced ? 'i' : 'p');
+  return NULL;
+  }
+
 static int init_imx_encoder(quicktime_t *file, int track)
   {
   quicktime_video_map_t *vtrack = &file->vtracks[track];
@@ -1138,7 +1373,7 @@
   codec->avctx->gop_size = 0;
   codec->avctx->intra_dc_precision = 2;
   codec->avctx->qmin = 1;
-  codec->avctx->qmax = 3;
+  codec->avctx->qmax = codec->imx_bitrate == 30 ? 8 : 3;
   codec->avctx->rtp_payload_size = 1; // ??
   codec->avctx->rc_buffer_aggressivity = 0.25;
   codec->avctx->flags |= CODEC_FLAG_INTERLACED_DCT|CODEC_FLAG_LOW_DELAY;
@@ -1185,6 +1420,105 @@
   return 0;
   }
 
+static int init_xdcam_hd422_encoder(quicktime_t *file, int track)
+  {
+  quicktime_video_map_t *vtrack = &file->vtracks[track];
+  quicktime_ffmpeg_video_codec_t *codec = vtrack->codec->priv;
+  quicktime_trak_t *trak = vtrack->track;
+  int height = trak->tkhd.track_height;
+  int time_scale = lqt_video_time_scale(file, track);
+  int frame_duration = lqt_frame_duration(file, track, NULL);
+  const char* fourcc;
+
+  codec->avctx->pix_fmt = PIX_FMT_YUV422P;
+  codec->avctx->gop_size = time_scale > 25 * frame_duration ? 15 : 12;
+  codec->avctx->max_b_frames = 2;
+  codec->avctx->intra_dc_precision = 2;
+  codec->avctx->qmin = 1;
+  codec->avctx->qmax = 12; // The maximum value compatible with non_linear_quant option.
+  codec->avctx->lmin = FF_QP2LAMBDA;
+
+  // XDCAM is meant to use open GOPs. From time to time we might want to insert closed GOPs
+  // like some other encoders do, but libavcodec only checks this flag once.
+  codec->avctx->flags &= ~CODEC_FLAG_CLOSED_GOP;
+
+  if(vtrack->interlace_mode != LQT_INTERLACE_NONE)
+    codec->avctx->flags |= CODEC_FLAG_INTERLACED_DCT|CODEC_FLAG_INTERLACED_ME;
+
+#if (LIBAVCODEC_VERSION_MAJOR < 54)
+  codec->avctx->flags2 |= CODEC_FLAG2_INTRA_VLC|CODEC_FLAG2_NON_LINEAR_QUANT;
+#else
+  av_dict_set(&codec->options, "non_linear_quant", "1", 0);
+  av_dict_set(&codec->options, "intra_vlc", "1", 0);
+#endif
+
+  codec->avctx->bit_rate = 50*1000*1000;
+  codec->avctx->rc_max_rate = codec->avctx->bit_rate;
+  codec->avctx->rc_min_rate = codec->avctx->bit_rate;
+  codec->avctx->rc_buffer_size = 17825792;
+  codec->avctx->rc_initial_buffer_occupancy = codec->avctx->rc_buffer_size;
+  codec->avctx->scenechange_threshold = 1000*1000*1000;
+
+  fourcc = get_xdcam_hd422_fourcc(file, track, height);
+  if (fourcc)
+    {
+    memcpy(trak->mdia.minf.stbl.stsd.table[0].format, fourcc, 4);
+    return 0;
+    }
+
+  return -1;
+  }
+
+#ifdef HAVE_PRORES_SUPPORT
+static int init_prores_encoder(quicktime_t *file, int track)
+  {
+  quicktime_video_map_t *vtrack = &file->vtracks[track];
+  quicktime_trak_t *trak = vtrack->track;
+  quicktime_ffmpeg_video_codec_t *codec = vtrack->codec->priv;
+  int height = trak->tkhd.track_height;
+
+  if(vtrack->interlace_mode != LQT_INTERLACE_NONE)
+    codec->avctx->flags |= CODEC_FLAG_INTERLACED_DCT;
+
+  // Color parameters go into ProRes bitstream.
+  if (trak->mdia.minf.stbl.stsd.table->has_colr)
+    {
+    // If COLR atom was provided by the client, use that.
+    const quicktime_colr_t* colr = &trak->mdia.minf.stbl.stsd.table->colr;
+    codec->avctx->color_primaries = colr->primaries;
+    codec->avctx->color_trc = colr->transferFunction;
+    codec->avctx->colorspace = colr->matrix;
+    }
+  else
+    {
+    // Try to guess the correct parameters.
+    if (height >= 720)
+      {
+      codec->avctx->color_primaries = AVCOL_PRI_BT709;
+      codec->avctx->color_trc = AVCOL_TRC_BT709;
+      codec->avctx->colorspace = AVCOL_SPC_BT709;
+      }
+    else if (height >= 576)
+      {
+      codec->avctx->color_primaries = AVCOL_PRI_BT470BG;
+      codec->avctx->color_trc = AVCOL_TRC_BT709;
+      codec->avctx->colorspace = AVCOL_SPC_SMPTE170M;
+      }
+    else
+      {
+      codec->avctx->color_primaries = AVCOL_PRI_SMPTE170M;
+      codec->avctx->color_trc = AVCOL_TRC_BT709;
+      codec->avctx->colorspace = AVCOL_SPC_SMPTE170M;
+      }
+    }
+
+  av_dict_set(&codec->options, "profile", lqt_prores_profiles[codec->prores_profile].ffmpeg_profile, 0);
+  memcpy(trak->mdia.minf.stbl.stsd.table[0].format, lqt_prores_profiles[codec->prores_profile].fourcc, 4);
+
+  return 0;
+  }
+#endif
+
 static void setup_header_mpeg4(quicktime_t *file, int track,
                                const uint8_t * header, int header_len,
                                int advanced)
@@ -1294,6 +1628,7 @@
 #endif
   int64_t pts;
   int kf;
+  uint8_t* encoded_data;
   
   if(!row_pointers)
     {
@@ -1323,10 +1658,23 @@
     /* time_base is 1/framerate for constant framerate */
           
     codec->avctx->time_base.den = lqt_video_time_scale(file, track);
-    codec->avctx->time_base.num = lqt_frame_duration(file, track, NULL);
+    codec->avctx->time_base.num = 1; // If we want variable frame durations, we need 1 here.
+    codec->encoding_pts_factor = 1;
 
-    //          codec->avctx->time_base.den = 1;
-    //          codec->avctx->time_base.num = lqt_video_time_scale(file, track);
+    // Codecs for which time_base.num == 1 causes problems.
+    switch(codec->encoder->id)
+      {
+      // Variable duration frames won't work for these.
+      case CODEC_ID_MPEG2VIDEO:
+      case CODEC_ID_DVVIDEO:
+      case CODEC_ID_DNXHD:
+          codec->encoding_pts_factor = lqt_frame_duration(file, track, NULL);
+          codec->avctx->time_base.num = codec->encoding_pts_factor;
+          // time_base may be reduced by a common factor by libavcodec,
+          // so we can't just use that.
+          break;
+      default:;
+      }
 
     if(codec->avctx->flags & CODEC_FLAG_QSCALE)
       codec->avctx->global_quality = codec->qscale;
@@ -1335,7 +1683,12 @@
     codec->avctx->height = height;
 
     lqt_ffmpeg_setup_encoding_colormodel(vtrack);
-
+#if ENCODE_VIDEO2
+    codec->frame->width = width;
+    codec->frame->height = height;
+    codec->frame->format = codec->avctx->pix_fmt;
+#endif
+    
     lqt_get_pixel_aspect(file, track, &pixel_width, &pixel_height);
     codec->avctx->sample_aspect_ratio.num = pixel_width;
     codec->avctx->sample_aspect_ratio.den = pixel_height;
@@ -1415,6 +1768,12 @@
       }
     else if(codec->is_imx)
       init_imx_encoder(file, track);
+    else if(codec->is_xdcam_hd422)
+      init_xdcam_hd422_encoder(file, track);
+#ifdef HAVE_PRORES_SUPPORT
+    else if(codec->encoder->id == CODEC_ID_PRORES)
+      init_prores_encoder(file, track);
+#endif
     
     /* Initialize 2-pass */
     if(codec->total_passes)
@@ -1515,10 +1874,10 @@
     codec->frame->linesize[2] = vtrack->stream_row_span_uv;
     }
   
-  codec->frame->pts = vtrack->timestamp;
+  codec->frame->pts = vtrack->timestamp / codec->encoding_pts_factor;
   if(codec->avctx->flags & CODEC_FLAG_QSCALE)
     codec->frame->quality = codec->qscale;
-#ifdef DO_INTERLACE
+#if 1
   if(vtrack->interlace_mode != LQT_INTERLACE_NONE)
     {
     codec->frame->interlaced_frame = 1;
@@ -1540,7 +1899,8 @@
   else
     bytes_encoded = 0;
   
-  pts = pkt.pts;
+  encoded_data = pkt.data; // May be different from codec->buffer!
+  pts = pkt.pts * codec->encoding_pts_factor;
   kf = !!(pkt.flags & AV_PKT_FLAG_KEY);
     
 #else // Old
@@ -1553,11 +1913,15 @@
   if(bytes_encoded < 0)
     return -1;
   
-  pts = codec->avctx->coded_frame->pts;
+  encoded_data = codec->buffer;
+  pts = codec->avctx->coded_frame->pts * encoding_pts_factor;
   kf = codec->avctx->coded_frame->key_frame;
   
 #endif
   
+  if(kf && codec->is_xdcam_hd422 && vtrack->cur_chunk)
+    kf = LQT_PARTIAL_KEY_FRAME; // For XDCAM, only the first key frame is full key frame.
+
   if(!was_initialized && codec->encoder->id == CODEC_ID_DNXHD)
     setup_avid_atoms(file, vtrack, codec->buffer, bytes_encoded);
   
@@ -1575,9 +1939,17 @@
                            kf);
           
     result = !quicktime_write_data(file, 
-                                   codec->buffer, 
+                                   encoded_data,
                                    bytes_encoded);
 
+#if ENCODE_VIDEO2
+    av_free_packet(&pkt);
+#endif
+
+    // Must go before lqt_write_frame_header() which increments vtrack->cur_chunk.
+    // cur_chunk is a frame number in storage order.
+    maybe_add_sdtp_entry(file, vtrack->cur_chunk, track);
+
     lqt_write_frame_footer(file, track);
           
     /* Write stats */
@@ -1642,7 +2014,7 @@
   else
     return 0;
   
-  pts = pkt.pts;
+  pts = pkt.pts * codec->encoding_pts_factor;
 
   kf = !!(pkt.flags & AV_PKT_FLAG_KEY);
   
@@ -1655,10 +2027,13 @@
   if(bytes_encoded <= 0)
     return 0;
 
-  pts = codec->avctx->coded_frame->pts;
+  pts = codec->avctx->coded_frame->pts * codec->encoding_pts_factor;
   kf = codec->avctx->coded_frame->key_frame;
   
 #endif
+
+  if(kf && codec->is_xdcam_hd422 && vtrack->cur_chunk)
+    kf = LQT_PARTIAL_KEY_FRAME; // For XDCAM, only the first key frame is full key frame.
   
   if(bytes_encoded)
     {
@@ -1669,6 +2044,10 @@
                                    codec->buffer, 
                                    bytes_encoded);
 
+    // Must go before lqt_write_frame_header() which increments vtrack->cur_chunk.
+    // cur_chunk is a frame number in storage order.
+    maybe_add_sdtp_entry(file, vtrack->cur_chunk, track);
+
     lqt_write_frame_footer(file, track);
           
     if((codec->pass == 1) && codec->avctx->stats_out && codec->stats_file)
@@ -1685,6 +2064,7 @@
                                const char *key, 
                                const void *value)
   {
+  int i;
   quicktime_video_map_t *vtrack = &file->vtracks[track];
   quicktime_ffmpeg_video_codec_t *codec = vtrack->codec->priv;
   if(!strcasecmp(key, "ff_qscale"))
@@ -1706,6 +2086,17 @@
       }
     return 0;
     }
+  else if(!strcasecmp(key, "prores_profile"))
+    {
+    for(i = 0; i < sizeof(lqt_prores_profiles)/sizeof(lqt_prores_profiles[0]); i++)
+      {
+      if(!strcasecmp((const char*)value, lqt_prores_profiles[i].lqt_name))
+        {
+        codec->prores_profile = i;
+        break;
+        }
+      }
+    }
   
   lqt_ffmpeg_set_parameter(codec->avctx,
 #if LIBAVCODEC_VERSION_MAJOR >= 54
@@ -1796,6 +2187,30 @@
   return 0;
   }
 
+static int init_compressed_xdcam_hd422(quicktime_t * file, int track)
+  {
+  quicktime_video_map_t * vtrack = &file->vtracks[track];
+
+  const char* fourcc = get_xdcam_hd422_fourcc(file, track, vtrack->ci.height);
+  if (fourcc)
+    {
+    memcpy(vtrack->track->mdia.minf.stbl.stsd.table[0].format, fourcc, 4);
+    return 0;
+    }
+  else
+    return -1;
+  }
+
+static int writes_compressed_xdcam_hd422(lqt_file_type_t type,
+                                         const lqt_compression_info_t * ci)
+  {
+    /* AVI doesn't support XDCAM family of formats */
+    if(type & (LQT_FILE_AVI | LQT_FILE_AVI_ODML))
+      return 0;
+
+    return ci->bitrate == 50000000;
+  }
+
 
 static void append_data_h264(lqt_packet_t * p, uint8_t * data, int len,
                              int header_len)
@@ -1888,11 +2303,15 @@
 #if LIBAVCODEC_VERSION_INT < ((53<<16)|(8<<8)|0)
   codec->avctx = avcodec_alloc_context();
 #else
-  codec->avctx = avcodec_alloc_context3(NULL);
+  codec->avctx = avcodec_alloc_context3((!vtrack || vtrack->do_encode) ? encoder : decoder);
 #endif
   codec->encoder = encoder;
   codec->decoder = decoder;
-  
+
+  // vtrack can be NULL if called from lqt_writes_compressed
+  if(vtrack)
+    quicktime_init_bframe_detector(&codec->bframe_detector, vtrack);
+
   codec_base->priv = codec;
   codec_base->delete_codec = lqt_ffmpeg_delete_video;
   codec_base->flush = flush;
@@ -1909,11 +2328,6 @@
       codec_base->init_compressed   = init_compressed_mpeg4;
       codec_base->write_packet = write_packet_mpeg4;
       }
-    else if(encoder->id == CODEC_ID_MPEG2VIDEO)
-      {
-      codec_base->writes_compressed = writes_compressed_imx;
-      codec_base->init_compressed   = init_compressed_imx;
-      }
     else if(encoder->id == CODEC_ID_DVVIDEO)
       {
       codec_base->init_compressed = init_compressed_dv;
@@ -1959,10 +2373,34 @@
           quicktime_match_32(compressor, "mx5p") ||
           quicktime_match_32(compressor, "mx3n") ||
           quicktime_match_32(compressor, "mx4n") ||
-          quicktime_match_32(compressor, "mx5n"))
+          quicktime_match_32(compressor, "mx5n") ||
+          quicktime_match_32(compressor, "AVmp"))
     {
     vtrack->stream_cmodel = BC_YUV422P;
     codec->is_imx = 1;
+    codec_base->writes_compressed = writes_compressed_imx;
+    codec_base->init_compressed   = init_compressed_imx;
+    }
+  else if(quicktime_match_32(compressor, "xd54") ||
+          quicktime_match_32(compressor, "xd55") ||
+          quicktime_match_32(compressor, "xd5a") ||
+          quicktime_match_32(compressor, "xd5b") ||
+          quicktime_match_32(compressor, "xd5c") ||
+          quicktime_match_32(compressor, "xd5d") ||
+          quicktime_match_32(compressor, "xd5e") ||
+          quicktime_match_32(compressor, "xd5f"))
+    {
+    vtrack->stream_cmodel = BC_YUV422P;
+    codec->is_xdcam_hd422 = 1;
+    codec_base->writes_compressed = writes_compressed_xdcam_hd422;
+    codec_base->init_compressed   = init_compressed_xdcam_hd422;
+    }
+  else if(quicktime_match_32(compressor, "apch") ||
+          quicktime_match_32(compressor, "apcn") ||
+          quicktime_match_32(compressor, "apcs") ||
+          quicktime_match_32(compressor, "apco"))
+    {
+    vtrack->stream_cmodel = BC_YUV422P10;
     }
   else
     vtrack->stream_cmodel = BC_YUV420P;
--- plugins/png/qtpng.c	2011-01-07 15:40:46.000000000 +0100
+++ plugins/png/qtpng.c	2013-03-19 11:29:58.000000000 +0100
@@ -25,6 +25,7 @@
 #include "lqt_private.h"
 #include <quicktime/colormodels.h>
 #include <png.h>
+#include <string.h>
 #include <stdlib.h>
 #include "qtpng.h"
 
--- plugins/schroedinger/extract_settings.c	2010-03-16 01:44:53.000000000 +0100
+++ plugins/schroedinger/extract_settings.c	2012-11-19 17:50:48.000000000 +0100
@@ -39,6 +39,7 @@
           fprintf(stderr, "    %s\n", s->enum_list[j]);
           j++;
           }
+        fprintf(stderr, "Default: %s\n", s->enum_list[(int)(s->default_value)]);
         break;
       case SCHRO_ENCODER_SETTING_TYPE_DOUBLE:
         fprintf(stderr, "Double\n");
--- src/Makefile.am	2010-03-21 02:29:41.000000000 +0100
+++ src/Makefile.am	2012-11-19 17:59:29.000000000 +0100
@@ -99,6 +99,8 @@
 stsd.c \
 stsdtable.c \
 stss.c \
+stps.c \
+sdtp.c \
 stsz.c \
 stts.c \
 texttrack.c \
@@ -123,6 +125,7 @@
 lqt_color.c \
 lqt_codecinfo.c \
 lqt_divx.c \
-lqt_qtvr.c
+lqt_qtvr.c \
+bframe_detector.c
 
 INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include
--- src/edts.c	2011-01-07 15:40:46.000000000 +0100
+++ src/edts.c	2012-12-21 14:37:09.000000000 +0100
@@ -43,14 +43,16 @@
 {
 	quicktime_atom_t leaf_atom;
 
-	do
+	while (quicktime_position(file) + 8 < edts_atom->end)
 	{
 		quicktime_atom_read_header(file, &leaf_atom);
 		if(quicktime_atom_is(&leaf_atom, "elst"))
-		{ quicktime_read_elst(file, &edts->elst); }
+			quicktime_read_elst(file, &edts->elst);
 		else
 			quicktime_atom_skip(file, &leaf_atom);
-	}while(quicktime_position(file) < edts_atom->end);
+	}
+
+	quicktime_set_position(file, edts_atom->end);
 }
 
 void quicktime_edts_dump(quicktime_edts_t *edts)
--- src/lqt_codecinfo.c	2011-01-07 15:40:46.000000000 +0100
+++ src/lqt_codecinfo.c	2012-04-27 17:19:52.000000000 +0200
@@ -601,7 +601,8 @@
   {
   char * pos;
   int ret;
-  char * filename;
+  char * filename = NULL;
+  size_t filename_len = 0, new_size = 0;
   DIR * directory;
   struct dirent * directory_entry;
   struct stat status;
@@ -611,8 +612,6 @@
   lqt_codec_info_t * video_codecs_end;
   lqt_codec_info_t * audio_codecs_end;
 
-  filename = malloc(PATH_MAX * sizeof(char));
-  
   /* Set the end pointers so we can quickly add codecs after */
 
   
@@ -662,6 +661,14 @@
     
     /* Now, the file should be a valid plugin, construct the filename */
     
+    new_size = strlen(plugin_dir) + strlen(directory_entry->d_name) + 2;
+    if (new_size > filename_len)
+      {
+      filename_len = new_size;
+      filename = realloc(filename, filename_len);
+      if (!filename)
+        exit(EXIT_FAILURE);
+      }
     strcpy(filename, plugin_dir);
     strcat(filename, "/");
     strcat(filename, directory_entry->d_name);
--- src/lqt_codecs.c	2011-01-07 15:40:46.000000000 +0100
+++ src/lqt_codecs.c	2012-11-19 17:51:13.000000000 +0100
@@ -540,8 +540,8 @@
   }
 
 void lqt_write_frame_header(quicktime_t * file, int track,
-                            int pic_num1,
-                            int64_t pic_pts, int keyframe)
+                            int pic_num1, int64_t pic_pts,
+                            enum LqtKeyFrame keyframe)
   {
   quicktime_video_map_t * vtrack = &file->vtracks[track];
   quicktime_trak_t * trak = vtrack->track;
@@ -590,8 +590,11 @@
   trak->chunk_samples = 1;
   quicktime_write_chunk_footer(file, trak);
   
-  if(vtrack->keyframe)
+  if(vtrack->keyframe == LQT_FULL_KEY_FRAME)
     quicktime_insert_keyframe(file, vtrack->cur_chunk, track);
+  else if(vtrack->keyframe == LQT_PARTIAL_KEY_FRAME)
+    quicktime_insert_partial_keyframe(file, vtrack->cur_chunk, track);
+
   vtrack->cur_chunk++;
   }
 
@@ -749,7 +752,22 @@
   if(file->vtracks[track].timecode_track)
     lqt_flush_timecode(file, track, time, 0);
   
-  file->vtracks[track].current_position++;
+  vtrack->current_position++;
+
+  /* vtrack->current_position now points past the last frame
+     we were asked to encode. If that frame was the last one
+     but flushing the codec produces more output, there will be
+     read access to vtrack->timestamps[vtrack->current_position]
+     from lqt_write_frame_header(), therefore we need to make sure
+     it's a valid address pointing to initialized memory. */
+  if(vtrack->current_position >= vtrack->timestamps_alloc)
+    {
+    vtrack->timestamps_alloc += 1024;
+    vtrack->timestamps = realloc(vtrack->timestamps,
+                                 vtrack->timestamps_alloc *
+                                 sizeof(*vtrack->timestamps));
+    }
+  vtrack->timestamps[vtrack->current_position] = -1;
   return 0;
   }
 
--- src/lqt_qtvr.c	2011-01-07 15:40:46.000000000 +0100
+++ src/lqt_qtvr.c	2013-01-12 14:02:30.000000000 +0100
@@ -202,6 +202,8 @@
         file->moov.udta.ctyp[3] = 'r';
         file->moov.udta.is_qtvr = 1;
 
+        file->moov.mvhd.time_scale = time_scale;
+
         trak = quicktime_add_track(file);
         quicktime_trak_init_qtvr(file, trak, QTVR_OBJ, width, height, duration, time_scale);
         quicktime_obji_init(&file->qtvr_node[0].obji);
@@ -225,6 +227,8 @@
         file->moov.udta.ctyp[3] = 'r';
         file->moov.udta.is_qtvr = 1;
 
+        file->moov.mvhd.time_scale = time_scale;
+
         trak = quicktime_add_track(file);
         quicktime_trak_init_qtvr(file, trak, QTVR_PAN, width, height, duration, time_scale);
         quicktime_pdat_init(&file->qtvr_node[0].pdat);
--- src/lqt_quicktime.c	2012-02-25 20:46:56.000000000 +0100
+++ src/lqt_quicktime.c	2012-11-19 17:59:29.000000000 +0100
@@ -1440,6 +1440,23 @@
   return 0;
   }
 
+long quicktime_get_partial_keyframe_before(quicktime_t *file, long frame, int track)
+  {
+  quicktime_trak_t *trak = file->vtracks[track].track;
+  quicktime_stps_t *stps = &trak->mdia.minf.stbl.stps;
+  int i;
+
+  // Offset 1
+  frame++;
+
+  for(i = stps->total_entries - 1; i >= 0; i--)
+    {
+    if(stps->table[i].sample <= frame) return stps->table[i].sample - 1;
+    }
+
+  return 0;
+  }
+
 #if 0
 static long quicktime_get_keyframe_after(quicktime_t *file, long frame, int track)
   {
@@ -1486,6 +1503,53 @@
   stss->total_entries++;
   }
 
+void quicktime_insert_partial_keyframe(quicktime_t *file, long frame, int track)
+  {
+  quicktime_trak_t *trak = file->vtracks[track].track;
+  quicktime_stps_t *stps = &trak->mdia.minf.stbl.stps;
+
+  if(file->file_type & (LQT_FILE_AVI|LQT_FILE_AVI_ODML))
+    {
+    // AVI doesn't support partial keyframes.
+    return;
+    }
+
+  // Expand table
+  if(stps->entries_allocated <= stps->total_entries)
+    {
+    stps->entries_allocated += 1024;
+    stps->table = realloc(stps->table,
+                          sizeof(*stps->table) *
+                          stps->entries_allocated);
+    }
+
+  stps->table[stps->total_entries].sample = frame+1;
+  stps->total_entries++;
+  }
+
+void quicktime_insert_sdtp_entry(quicktime_t *file, long sample, int track, uint8_t flags)
+  {
+  quicktime_trak_t *trak = file->vtracks[track].track;
+  quicktime_sdtp_t *sdtp = &trak->mdia.minf.stbl.sdtp;
+
+  if(file->file_type & (LQT_FILE_AVI|LQT_FILE_AVI_ODML))
+    {
+    // AVI doesn't support sdtp atom
+    return;
+    }
+
+  // Expand table
+  if(sdtp->entries_allocated <= sample)
+    {
+    sdtp->entries_allocated = sdtp->entries_allocated * 2 + 512;
+    sdtp->table = realloc(sdtp->table, sdtp->entries_allocated);
+    memset(sdtp->table + sdtp->total_entries, 0, sdtp->entries_allocated - sdtp->total_entries);
+    }
+
+  sdtp->table[sample] = flags;
+  if(sdtp->total_entries <= sample)
+    sdtp->total_entries = sample + 1;
+  }
 
 int quicktime_has_keyframes(quicktime_t *file, int track)
   {
@@ -1521,6 +1585,7 @@
   vtrack->current_position = 0;
   vtrack->cur_chunk = 0;
   vtrack->io_cmodel = BC_RGB888;
+  vtrack->do_encode = encode;
   quicktime_init_vcodec(vtrack, encode, info);
   return 0;
   }
@@ -1625,6 +1690,7 @@
       quicktime_init_video_map(&file->vtracks[i],
                                file->wr,
                                (lqt_codec_info_t*)0);
+#if 0
       /* Get decoder colormodel */
       file->vtracks[i].codec->decode_video(file, (uint8_t**)0, i);
       file->vtracks[i].io_cmodel = file->vtracks[i].stream_cmodel;
@@ -1633,7 +1699,7 @@
                               quicktime_video_width(file, i),
                               &file->vtracks[i].stream_row_span,
                               &file->vtracks[i].stream_row_span_uv);
-
+#endif
       /* Get interlace mode */
       if((file->vtracks[i].interlace_mode == LQT_INTERLACE_NONE) &&
          (file->vtracks[i].track->mdia.minf.stbl.stsd.table[0].has_fiel))
@@ -2054,9 +2120,7 @@
       free(new_file);
     new_file = 0;
     }
-        
-        
-        
+       
   if(rd && new_file)
     {
     /* Set default decoding parameters */
@@ -2064,7 +2128,21 @@
       lqt_set_default_audio_parameters(new_file, i);
 
     for(i = 0; i < new_file->total_vtracks; i++)
+      {
       lqt_set_default_video_parameters(new_file, i);
+      
+      /*
+       *  Get decoder colormodel
+       *  This might causing a first frame to be decoded, so we can't call this
+       *  before setting the parameters
+       */
+      new_file->vtracks[i].codec->decode_video(new_file, (uint8_t**)0, i);
+      new_file->vtracks[i].io_cmodel = new_file->vtracks[i].stream_cmodel;
+      lqt_get_default_rowspan(new_file->vtracks[i].stream_cmodel,
+                              quicktime_video_width(new_file, i),
+                              &new_file->vtracks[i].stream_row_span,
+                              &new_file->vtracks[i].stream_row_span_uv);
+      }
     }
         
   return new_file;
--- src/stbl.c	2011-01-07 15:40:47.000000000 +0100
+++ src/stbl.c	2012-11-19 17:59:29.000000000 +0100
@@ -31,8 +31,10 @@
   quicktime_stsd_init(&stbl->stsd);
   quicktime_stts_init(&stbl->stts);
   quicktime_stss_init(&stbl->stss);
+  quicktime_stps_init(&stbl->stps);
   quicktime_stsc_init(&stbl->stsc);
   quicktime_stsz_init(&stbl->stsz);
+  quicktime_sdtp_init(&stbl->sdtp);
   quicktime_stco_init(&stbl->stco);
   }
 
@@ -135,8 +137,10 @@
   quicktime_stsd_delete(&stbl->stsd);
   quicktime_stts_delete(&stbl->stts);
   quicktime_stss_delete(&stbl->stss);
+  quicktime_stps_delete(&stbl->stps);
   quicktime_stsc_delete(&stbl->stsc);
   quicktime_stsz_delete(&stbl->stsz);
+  quicktime_sdtp_delete(&stbl->sdtp);
   quicktime_stco_delete(&stbl->stco);
   }
 
@@ -147,8 +151,12 @@
   quicktime_stts_dump(&stbl->stts);
   if(stbl->stss.total_entries)
     quicktime_stss_dump(&stbl->stss);
+  if(stbl->stps.total_entries)
+    quicktime_stps_dump(&stbl->stps);
   quicktime_stsc_dump(&stbl->stsc);
   quicktime_stsz_dump(&stbl->stsz);
+  if(stbl->sdtp.total_entries)
+    quicktime_sdtp_dump(&stbl->sdtp);
   quicktime_stco_dump(&stbl->stco);
   if(stbl->has_ctts)
     quicktime_ctts_dump(&stbl->ctts);
@@ -187,6 +195,11 @@
       quicktime_read_stss(file, &stbl->stss);
       quicktime_atom_skip(file, &leaf_atom);
       }
+    else if(quicktime_atom_is(&leaf_atom, "stps"))
+      {
+      quicktime_read_stps(file, &stbl->stps);
+      quicktime_atom_skip(file, &leaf_atom);
+      }
     else if(quicktime_atom_is(&leaf_atom, "stsc"))
       {
       quicktime_read_stsc(file, &stbl->stsc);
@@ -197,6 +210,15 @@
       quicktime_read_stsz(file, &stbl->stsz);
       quicktime_atom_skip(file, &leaf_atom);
       }
+    else if(quicktime_atom_is(&leaf_atom, "sdtp"))
+      {
+      // This atom doesn't have its own number_of_entries field.
+      long num_entries = stbl->stsz.total_entries; // That's what Apple docs tell us to use.
+      if(num_entries <= 0)
+        num_entries = leaf_atom.size - 12; // Fallback, in case stsz wasn't loaded yet.
+      quicktime_read_sdtp(file, &stbl->sdtp, num_entries);
+      quicktime_atom_skip(file, &leaf_atom);
+      }
     else if(quicktime_atom_is(&leaf_atom, "co64"))
       {
       quicktime_read_stco64(file, &stbl->stco);
@@ -222,8 +244,16 @@
   quicktime_write_stsd(file, minf, &stbl->stsd);
   quicktime_write_stts(file, &stbl->stts);
   quicktime_write_stss(file, &stbl->stss);
+  if(stbl->stps.total_entries)
+    quicktime_write_stps(file, &stbl->stps);
   quicktime_write_stsc(file, &stbl->stsc);
   quicktime_write_stsz(file, &stbl->stsz);
+
+  // Must go after stsz, as it doesn't have its own number_of_entries field
+  // and Apple docs say to use stsz.number_of_entries.
+  if(stbl->sdtp.total_entries)
+    quicktime_write_sdtp(file, &stbl->sdtp);
+
   quicktime_write_stco(file, &stbl->stco);
   if(stbl->has_ctts)
     quicktime_write_ctts(file, &stbl->ctts);
--- src/stsdtable.c	2011-01-07 15:40:47.000000000 +0100
+++ src/stsdtable.c	2012-11-27 16:52:47.000000000 +0100
@@ -707,10 +707,13 @@
 
   table->version = 0;
   table->revision = 0;
-  table->vendor[0] = 'l';
-  table->vendor[1] = 'q';
-  table->vendor[2] = 't';
-  table->vendor[3] = ' ';
+  
+  /* We used to write "lqt " here, but some broken
+     software expects "appl" */
+  table->vendor[0] = 'a';
+  table->vendor[1] = 'p';
+  table->vendor[2] = 'p';
+  table->vendor[3] = 'l';
 
   table->temporal_quality = 100;
   table->spatial_quality = 258;
--- src/trak.c	2012-02-25 20:46:56.000000000 +0100
+++ src/trak.c	2013-05-07 11:30:01.000000000 +0200
@@ -427,7 +427,7 @@
   int64_t result = 0;
 
   if(trak->mdia.minf.stbl.stco.total_entries && 
-     chunk > trak->mdia.minf.stbl.stco.total_entries)
+     chunk >= trak->mdia.minf.stbl.stco.total_entries)
     result = table[trak->mdia.minf.stbl.stco.total_entries - 1].offset;
   else
     if(trak->mdia.minf.stbl.stco.total_entries)
--- /dev/null
+++ src/bframe_detector.c	2012-06-12 18:30:57.000000000 +0200
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ trak.c
+
+ libquicktime - A library for reading and writing quicktime/avi/mp4 files.
+ http://libquicktime.sourceforge.net
+
+ Copyright (C) 2002 Heroine Virtual Ltd.
+ Copyright (C) 2002-2011 Members of the libquicktime project.
+
+ This library is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 2.1 of the License, or (at your option)
+ any later version.
+
+ This library is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ details.
+
+ You should have received a copy of the GNU Lesser General Public License along
+ with this library; if not, write to the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*******************************************************************************/ 
+
+#include "lqt_private.h"
+
+void quicktime_init_bframe_detector(quicktime_bframe_detector* ctx, quicktime_video_map_t* vtrack)
+  {
+  ctx->frame = 0;
+  ctx->ctts_entry_idx = 0;
+  ctx->sample_within_entry = 0;
+  ctx->ctts = &vtrack->track->mdia.minf.stbl.ctts;
+  }
+
+/* Returns 1 for true, 0 for false, or a negative value if impossible to tell. */
+int quicktime_is_bframe(quicktime_bframe_detector* ctx, int64_t frame)
+  {
+
+  if(ctx->ctts_entry_idx < 0 || ctx->ctts_entry_idx >= ctx->ctts->total_entries)
+    return -1;
+
+  if(frame > ctx->frame)
+    {
+    while(frame - ctx->frame >= ctx->ctts->table[ctx->ctts_entry_idx].sample_count - ctx->sample_within_entry)
+      {
+      if(ctx->ctts_entry_idx + 1 >= ctx->ctts->total_entries)
+        return -1;
+
+      ctx->frame += ctx->ctts->table[ctx->ctts_entry_idx].sample_count - ctx->sample_within_entry;
+      ctx->ctts_entry_idx++;
+      ctx->sample_within_entry = 0;
+      }
+    ctx->sample_within_entry += frame - ctx->frame;
+    ctx->frame = frame;
+    }
+  else if(frame < ctx->frame)
+    {
+    while(ctx->frame - frame > ctx->sample_within_entry)
+      {
+      if(ctx->ctts_entry_idx < 1)
+        return -1;
+
+      ctx->frame -= ctx->sample_within_entry + 1;
+      ctx->ctts_entry_idx--;
+      ctx->sample_within_entry = ctx->ctts->table[ctx->ctts_entry_idx].sample_count - 1;
+      }
+    ctx->sample_within_entry -= ctx->frame - frame;
+    ctx->frame = frame;
+    }
+
+    return ctx->ctts->table[ctx->ctts_entry_idx].sample_duration < 
+       ctx->ctts->table[0].sample_duration;;
+  }
--- /dev/null
+++ src/sdtp.c	2012-11-20 10:51:21.000000000 +0100
@@ -0,0 +1,130 @@
+/*******************************************************************************
+ sdtp.c
+
+ libquicktime - A library for reading and writing quicktime/avi/mp4 files.
+ http://libquicktime.sourceforge.net
+
+ Copyright (C) 2002-2011 Members of the libquicktime project.
+
+ This library is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 2.1 of the License, or (at your option)
+ any later version.
+
+ This library is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ details.
+
+ You should have received a copy of the GNU Lesser General Public License along
+ with this library; if not, write to the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*******************************************************************************/ 
+
+#include "lqt_private.h"
+#include <stdlib.h>
+#include <string.h>
+
+void quicktime_sdtp_init(quicktime_sdtp_t *sdtp)
+  {
+  sdtp->version = 0;
+  sdtp->flags = 0;
+  sdtp->total_entries = 0;
+  sdtp->entries_allocated = 0;
+  sdtp->table = NULL;
+  }
+
+void quicktime_sdtp_delete(quicktime_sdtp_t *sdtp)
+  {
+  if(sdtp->table) free(sdtp->table);
+  sdtp->total_entries = 0;
+  sdtp->entries_allocated = 0;
+  sdtp->table = 0;
+  }
+
+void quicktime_sdtp_dump(quicktime_sdtp_t *sdtp)
+  {
+  long i;
+  lqt_dump("     sample dependencies (sdtp)\n");
+  lqt_dump("      version %d\n", sdtp->version);
+  lqt_dump("      flags %ld\n", sdtp->flags);
+  lqt_dump("      total_entries %ld\n", sdtp->total_entries);
+  for(i = 0; i < sdtp->total_entries; i++)
+    {
+    unsigned flags = sdtp->table[i];
+    char separator = ':';
+    lqt_dump("       sample %ld: flags 0x%02x", i, flags);
+    if(flags & 1)
+      {
+      lqt_dump("%c has_redundant_coding", separator);
+      separator = ',';
+      }
+    if(flags & 2)
+      {
+      lqt_dump("%c no_redundant_coding", separator);
+      separator = ',';
+      }
+    if(flags & 4)
+      {
+      lqt_dump("%c other_samples_depend_on_this_one", separator);
+      separator = ',';
+      }
+    if(flags & 8)
+      {
+      lqt_dump("%c no_other_samples_depend_on_this_one", separator);
+      separator = ',';
+      }
+    if(flags & 16)
+      {
+      lqt_dump("%c sample_depends_on_others", separator);
+      separator = ',';
+      }
+    if(flags & 32)
+      {
+      lqt_dump("%c sample_doesnt_depend_on_others", separator);
+      separator = ',';
+      }
+    if(flags & 64)
+      {
+      lqt_dump("%c earlier_display_times_allowed", separator);
+      separator = ',';
+      }
+    if(flags & 128)
+      {
+      lqt_dump("%c reserved_bit_7", separator);
+      separator = ',';
+      }
+    lqt_dump("\n");
+    }
+  }
+
+void quicktime_read_sdtp(quicktime_t *file, quicktime_sdtp_t *sdtp, long num_entries)
+  {
+  sdtp->version = quicktime_read_char(file);
+  sdtp->flags = quicktime_read_int24(file);
+  sdtp->total_entries = num_entries;
+
+  if(sdtp->entries_allocated < sdtp->total_entries)
+    {
+    sdtp->entries_allocated = sdtp->total_entries;
+    sdtp->table = (uint8_t*)realloc(sdtp->table, sdtp->entries_allocated);
+    }
+
+  memset(sdtp->table, 0, sdtp->total_entries);
+  quicktime_read_data(file, sdtp->table, sdtp->total_entries);
+  }
+
+void quicktime_write_sdtp(quicktime_t *file, quicktime_sdtp_t *sdtp)
+  {
+  quicktime_atom_t atom;
+
+  if(sdtp->total_entries)
+    {
+    quicktime_atom_write_header(file, &atom, "sdtp");
+
+    quicktime_write_char(file, sdtp->version);
+    quicktime_write_int24(file, sdtp->flags);
+    quicktime_write_data(file, sdtp->table, sdtp->total_entries);
+    quicktime_atom_write_footer(file, &atom);
+    }
+  }
--- /dev/null
+++ src/stps.c	2012-06-08 15:56:39.000000000 +0200
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ stps.c
+
+ libquicktime - A library for reading and writing quicktime/avi/mp4 files.
+ http://libquicktime.sourceforge.net
+
+ Copyright (C) 2002 Heroine Virtual Ltd.
+ Copyright (C) 2002-2011 Members of the libquicktime project.
+
+ This library is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 2.1 of the License, or (at your option)
+ any later version.
+
+ This library is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ details.
+
+ You should have received a copy of the GNU Lesser General Public License along
+ with this library; if not, write to the Free Software Foundation, Inc., 51
+ Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*******************************************************************************/ 
+
+#include "lqt_private.h"
+#include <stdlib.h>
+
+void quicktime_stps_init(quicktime_stps_t *stps)
+  {
+  stps->version = 0;
+  stps->flags = 0;
+  stps->total_entries = 0;
+  stps->entries_allocated = 0;
+  stps->table = NULL;
+  }
+
+void quicktime_stps_delete(quicktime_stps_t *stps)
+  {
+  if(stps->table) free(stps->table);
+  stps->total_entries = 0;
+  stps->entries_allocated = 0;
+  stps->table = 0;
+  }
+
+void quicktime_stps_dump(quicktime_stps_t *stps)
+  {
+  int i;
+  lqt_dump("     partial sync sample (stps)\n");
+  lqt_dump("      version %d\n", stps->version);
+  lqt_dump("      flags %ld\n", stps->flags);
+  lqt_dump("      total_entries %ld\n", stps->total_entries);
+  for(i = 0; i < stps->total_entries; i++)
+    {
+    lqt_dump("       sample %lx\n", stps->table[i].sample);
+    }
+  }
+
+void quicktime_read_stps(quicktime_t *file, quicktime_stps_t *stps)
+  {
+  int i;
+  stps->version = quicktime_read_char(file);
+  stps->flags = quicktime_read_int24(file);
+  stps->total_entries = quicktime_read_int32(file);
+
+  if(stps->entries_allocated < stps->total_entries)
+    {
+    stps->entries_allocated = stps->total_entries;
+    stps->table = (quicktime_stps_table_t*)realloc(stps->table, sizeof(quicktime_stps_table_t) * stps->entries_allocated);
+    }
+
+  for(i = 0; i < stps->total_entries; i++)
+    {
+    stps->table[i].sample = quicktime_read_int32(file);
+    }
+  }
+
+
+void quicktime_write_stps(quicktime_t *file, quicktime_stps_t *stps)
+  {
+  int i;
+  quicktime_atom_t atom;
+
+  if(stps->total_entries)
+    {
+    quicktime_atom_write_header(file, &atom, "stps");
+
+    quicktime_write_char(file, stps->version);
+    quicktime_write_int24(file, stps->flags);
+    quicktime_write_int32(file, stps->total_entries);
+    for(i = 0; i < stps->total_entries; i++)
+      {
+      quicktime_write_int32(file, stps->table[i].sample);
+      }
+
+    quicktime_atom_write_footer(file, &atom);
+    }
+  }
