+
+ return 0;
+}
+
+/*
+ * st->disposition controls the "enabled" flag in the tkhd tag.
+ * QuickTime will not play a track if it is not enabled. So make sure
+ * that one track of each type (audio, video, subtitle) is enabled.
+ *
+ * Subtitles are special. For audio and video, setting "enabled" also
+ * makes the track "default" (i.e. it is rendered when played). For
+ * subtitles, an "enabled" subtitle is not rendered by default, but
+ * if no subtitle is enabled, the subtitle menu in QuickTime will be
+ * empty!
+ */
+static void enable_tracks(AVFormatContext *s)
+{
+ MOVMuxContext *mov = s->priv_data;
+ int i;
+ int enabled[AVMEDIA_TYPE_NB];
+ int first[AVMEDIA_TYPE_NB];
+
+ for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
+ enabled[i] = 0;
+ first[i] = -1;
+ }
+
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
+
+ if (st->codec->codec_type <= AVMEDIA_TYPE_UNKNOWN ||
+ st->codec->codec_type >= AVMEDIA_TYPE_NB)
+ continue;
+
+ if (first[st->codec->codec_type] < 0)
+ first[st->codec->codec_type] = i;
+ if (st->disposition & AV_DISPOSITION_DEFAULT) {
+ mov->tracks[i].flags |= MOV_TRACK_ENABLED;
+ enabled[st->codec->codec_type]++;
+ }
+ }
+
+ for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
+ switch (i) {
+ case AVMEDIA_TYPE_VIDEO:
+ case AVMEDIA_TYPE_AUDIO:
+ case AVMEDIA_TYPE_SUBTITLE:
+ if (enabled[i] > 1)
+ mov->per_stream_grouping = 1;
+ if (!enabled[i] && first[i] >= 0)
+ mov->tracks[first[i]].flags |= MOV_TRACK_ENABLED;
+ break;
+ }
+ }
+}
+
+static void mov_free(AVFormatContext *s)
+{
+ MOVMuxContext *mov = s->priv_data;
+ int i;
+
+ if (mov->chapter_track) {
+ if (mov->tracks[mov->chapter_track].enc)
+ av_free(mov->tracks[mov->chapter_track].enc->extradata);
+ av_freep(&mov->tracks[mov->chapter_track].enc);
+ }
+
+ for (i = 0; i < mov->nb_streams; i++) {
+ if (mov->tracks[i].tag == MKTAG('r','t','p',' '))
+ ff_mov_close_hinting(&mov->tracks[i]);
+ av_freep(&mov->tracks[i].cluster);
+ av_freep(&mov->tracks[i].frag_info);
+
+ if (mov->tracks[i].vos_len)
+ av_free(mov->tracks[i].vos_data);
+ }
+
+ av_freep(&mov->tracks);
+}
+
+static uint32_t rgb_to_yuv(uint32_t rgb)
+{
+ uint8_t r, g, b;
+ int y, cb, cr;
+
+ r = (rgb >> 16) & 0xFF;
+ g = (rgb >> 8) & 0xFF;
+ b = (rgb ) & 0xFF;
+
+ y = av_clip_uint8( 16. + 0.257 * r + 0.504 * g + 0.098 * b);
+ cb = av_clip_uint8(128. - 0.148 * r - 0.291 * g + 0.439 * b);
+ cr = av_clip_uint8(128. + 0.439 * r - 0.368 * g - 0.071 * b);
+
+ return (y << 16) | (cr << 8) | cb;
+}
+
+static int mov_create_dvd_sub_decoder_specific_info(MOVTrack *track,
+ AVStream *st)
+{
+ int i, width = 720, height = 480;
+ int have_palette = 0, have_size = 0;
+ uint32_t palette[16];
+ char *cur = st->codec->extradata;
+
+ while (cur && *cur) {
+ if (strncmp("palette:", cur, 8) == 0) {
+ int i, count;
+ count = sscanf(cur + 8,
+ "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
+ "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
+ "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
+ "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32"",
+ &palette[ 0], &palette[ 1], &palette[ 2], &palette[ 3],
+ &palette[ 4], &palette[ 5], &palette[ 6], &palette[ 7],
+ &palette[ 8], &palette[ 9], &palette[10], &palette[11],
+ &palette[12], &palette[13], &palette[14], &palette[15]);
+
+ for (i = 0; i < count; i++) {
+ palette[i] = rgb_to_yuv(palette[i]);
+ }
+ have_palette = 1;
+ } else if (!strncmp("size:", cur, 5)) {
+ sscanf(cur + 5, "%dx%d", &width, &height);
+ have_size = 1;
+ }
+ if (have_palette && have_size)
+ break;
+ cur += strcspn(cur, "\n\r");
+ cur += strspn(cur, "\n\r");
+ }
+ if (have_palette) {
+ track->vos_data = av_malloc(16*4);
+ if (!track->vos_data)
+ return AVERROR(ENOMEM);
+ for (i = 0; i < 16; i++) {
+ AV_WB32(track->vos_data + i * 4, palette[i]);
+ }
+ track->vos_len = 16 * 4;
+ }
+ st->codec->width = width;
+ st->codec->height = track->height = height;
+
+ return 0;