X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fmovenc.c;h=8196b73077f5f56b35c94001be5e35f14ae8fde7;hb=ec7ecb88117fd2d086f0be45ded9743c94100ef4;hp=d5eb25bcc2507bb7daa61ed80a291fa8c1a4c0bb;hpb=82edf6727f0663601351081ca1e4fb20d1752972;p=ffmpeg diff --git a/libavformat/movenc.c b/libavformat/movenc.c index d5eb25bcc25..8196b73077f 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -52,7 +52,7 @@ static const AVOption options[] = { { "separate_moof", "Write separate moof/mdat atoms for each track", 0, AV_OPT_TYPE_CONST, {.dbl = FF_MOV_FLAG_SEPARATE_MOOF}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, { "frag_custom", "Flush fragments on caller requests", 0, AV_OPT_TYPE_CONST, {.dbl = FF_MOV_FLAG_FRAG_CUSTOM}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, { "isml", "Create a live smooth streaming feed (for pushing to a publishing point)", 0, AV_OPT_TYPE_CONST, {.dbl = FF_MOV_FLAG_ISML}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, - FF_RTP_FLAG_OPTS(MOVMuxContext, rtp_flags) + FF_RTP_FLAG_OPTS(MOVMuxContext, rtp_flags), { "skip_iods", "Skip writing iods atom.", offsetof(MOVMuxContext, iods_skip), AV_OPT_TYPE_INT, {.dbl = 1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM}, { "iods_audio_profile", "iods audio profile atom.", offsetof(MOVMuxContext, iods_audio_profile), AV_OPT_TYPE_INT, {.dbl = -1}, -1, 255, AV_OPT_FLAG_ENCODING_PARAM}, { "iods_video_profile", "iods video profile atom.", offsetof(MOVMuxContext, iods_video_profile), AV_OPT_TYPE_INT, {.dbl = -1}, -1, 255, AV_OPT_FLAG_ENCODING_PARAM}, @@ -859,6 +859,7 @@ static const struct { uint32_t tag; unsigned bps; } mov_pix_fmt_tags[] = { + { PIX_FMT_YUYV422, MKTAG('y','u','v','2'), 0 }, { PIX_FMT_YUYV422, MKTAG('y','u','v','s'), 0 }, { PIX_FMT_UYVY422, MKTAG('2','v','u','y'), 0 }, { PIX_FMT_RGB555BE,MKTAG('r','a','w',' '), 16 }, @@ -881,7 +882,7 @@ static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track) int i; for (i = 0; i < FF_ARRAY_ELEMS(mov_pix_fmt_tags); i++) { - if (track->enc->pix_fmt == mov_pix_fmt_tags[i].pix_fmt) { + if (track->enc->codec_tag == mov_pix_fmt_tags[i].tag && track->enc->pix_fmt == mov_pix_fmt_tags[i].pix_fmt) { tag = mov_pix_fmt_tags[i].tag; track->enc->bits_per_coded_sample = mov_pix_fmt_tags[i].bps; break; @@ -1072,9 +1073,10 @@ static int mov_write_video_tag(AVIOContext *pb, MOVTrack *track) mov_write_d263_tag(pb); else if(track->enc->codec_id == CODEC_ID_SVQ3) mov_write_svq3_tag(pb); - else if(track->enc->codec_id == CODEC_ID_AVUI) + else if(track->enc->codec_id == CODEC_ID_AVUI) { mov_write_extradata_tag(pb, track); - else if(track->enc->codec_id == CODEC_ID_DNXHD) + avio_wb32(pb, 0); + } else if(track->enc->codec_id == CODEC_ID_DNXHD) mov_write_avid_tag(pb, track); else if(track->enc->codec_id == CODEC_ID_H264) { mov_write_avcc_tag(pb, track); @@ -1505,11 +1507,30 @@ static int mov_write_mdia_tag(AVIOContext *pb, MOVTrack *track) return update_size(pb, pos); } +/* transformation matrix + |a b u| + |c d v| + |tx ty w| */ +static void write_matrix(AVIOContext *pb, int16_t a, int16_t b, int16_t c, + int16_t d, int16_t tx, int16_t ty) +{ + avio_wb32(pb, a << 16); /* 16.16 format */ + avio_wb32(pb, b << 16); /* 16.16 format */ + avio_wb32(pb, 0); /* u in 2.30 format */ + avio_wb32(pb, c << 16); /* 16.16 format */ + avio_wb32(pb, d << 16); /* 16.16 format */ + avio_wb32(pb, 0); /* v in 2.30 format */ + avio_wb32(pb, tx << 16); /* 16.16 format */ + avio_wb32(pb, ty << 16); /* 16.16 format */ + avio_wb32(pb, 1 << 30); /* w in 2.30 format */ +} + static int mov_write_tkhd_tag(AVIOContext *pb, MOVTrack *track, AVStream *st) { int64_t duration = av_rescale_rnd(track->track_duration, MOV_TIMESCALE, track->timescale, AV_ROUND_UP); int version = duration < INT32_MAX ? 0 : 1; + int rotation = 0; if (track->mode == MODE_ISM) version = 1; @@ -1544,16 +1565,19 @@ static int mov_write_tkhd_tag(AVIOContext *pb, MOVTrack *track, AVStream *st) avio_wb16(pb, 0); /* reserved */ /* Matrix structure */ - avio_wb32(pb, 0x00010000); /* reserved */ - avio_wb32(pb, 0x0); /* reserved */ - avio_wb32(pb, 0x0); /* reserved */ - avio_wb32(pb, 0x0); /* reserved */ - avio_wb32(pb, 0x00010000); /* reserved */ - avio_wb32(pb, 0x0); /* reserved */ - avio_wb32(pb, 0x0); /* reserved */ - avio_wb32(pb, 0x0); /* reserved */ - avio_wb32(pb, 0x40000000); /* reserved */ - + if (st && st->metadata) { + AVDictionaryEntry *rot = av_dict_get(st->metadata, "rotate", NULL, 0); + rotation = (rot && rot->value) ? atoi(rot->value) : 0; + } + if (rotation == 90) { + write_matrix(pb, 0, 1, -1, 0, track->enc->height, 0); + } else if (rotation == 180) { + write_matrix(pb, -1, 0, 0, -1, track->enc->width, track->enc->height); + } else if (rotation == 270) { + write_matrix(pb, 0, -1, 1, 0, 0, track->enc->width); + } else { + write_matrix(pb, 1, 0, 0, 1, 0, 0); + } /* Track width and height, for visual only */ if(st && (track->enc->codec_type == AVMEDIA_TYPE_VIDEO || track->enc->codec_type == AVMEDIA_TYPE_SUBTITLE)) { @@ -1814,15 +1838,7 @@ static int mov_write_mvhd_tag(AVIOContext *pb, MOVMuxContext *mov) avio_wb32(pb, 0); /* reserved */ /* Matrix structure */ - avio_wb32(pb, 0x00010000); /* reserved */ - avio_wb32(pb, 0x0); /* reserved */ - avio_wb32(pb, 0x0); /* reserved */ - avio_wb32(pb, 0x0); /* reserved */ - avio_wb32(pb, 0x00010000); /* reserved */ - avio_wb32(pb, 0x0); /* reserved */ - avio_wb32(pb, 0x0); /* reserved */ - avio_wb32(pb, 0x0); /* reserved */ - avio_wb32(pb, 0x40000000); /* reserved */ + write_matrix(pb, 1, 0, 0, 1, 0, 0); avio_wb32(pb, 0); /* reserved (preview time) */ avio_wb32(pb, 0); /* reserved (preview duration) */ @@ -2078,7 +2094,10 @@ static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov, mov_write_string_metadata(s, pb_buf, "\251alb", "album" , 0); mov_write_string_metadata(s, pb_buf, "\251day", "date" , 0); mov_write_string_metadata(s, pb_buf, "\251swr", "encoder" , 0); + // currently ignored by mov.c mov_write_string_metadata(s, pb_buf, "\251des", "comment" , 0); + // add support for libquicktime, this atom is also actually read by mov.c + mov_write_string_metadata(s, pb_buf, "\251cmt", "comment" , 0); mov_write_string_metadata(s, pb_buf, "\251gen", "genre" , 0); mov_write_string_metadata(s, pb_buf, "\251cpy", "copyright" , 0); } else { @@ -3371,7 +3390,8 @@ static int mov_write_header(AVFormatContext *s) av_log(s, AV_LOG_WARNING, "track %d: codec frame size is not set\n", i); track->audio_vbr = 1; }else if(st->codec->codec_id == CODEC_ID_ADPCM_MS || - st->codec->codec_id == CODEC_ID_ADPCM_IMA_WAV){ + st->codec->codec_id == CODEC_ID_ADPCM_IMA_WAV || + st->codec->codec_id == CODEC_ID_ILBC){ if (!st->codec->block_align) { av_log(s, AV_LOG_ERROR, "track %d: codec block align is not set for adpcm\n", i); goto error; @@ -3562,15 +3582,12 @@ static int mov_write_trailer(AVFormatContext *s) MOV_CLASS(mov) AVOutputFormat ff_mov_muxer = { .name = "mov", - .long_name = NULL_IF_CONFIG_SMALL("MOV format"), + .long_name = NULL_IF_CONFIG_SMALL("QuickTime / MOV"), .extensions = "mov", .priv_data_size = sizeof(MOVMuxContext), .audio_codec = CODEC_ID_AAC, -#if CONFIG_LIBX264_ENCODER - .video_codec = CODEC_ID_H264, -#else - .video_codec = CODEC_ID_MPEG4, -#endif + .video_codec = CONFIG_LIBX264_ENCODER ? + CODEC_ID_H264 : CODEC_ID_MPEG4, .write_header = mov_write_header, .write_packet = mov_write_packet, .write_trailer = mov_write_trailer, @@ -3585,7 +3602,7 @@ AVOutputFormat ff_mov_muxer = { MOV_CLASS(tgp) AVOutputFormat ff_tgp_muxer = { .name = "3gp", - .long_name = NULL_IF_CONFIG_SMALL("3GP format"), + .long_name = NULL_IF_CONFIG_SMALL("3GP (3GPP file format)"), .extensions = "3gp", .priv_data_size = sizeof(MOVMuxContext), .audio_codec = CODEC_ID_AMR_NB, @@ -3602,16 +3619,13 @@ AVOutputFormat ff_tgp_muxer = { MOV_CLASS(mp4) AVOutputFormat ff_mp4_muxer = { .name = "mp4", - .long_name = NULL_IF_CONFIG_SMALL("MP4 format"), + .long_name = NULL_IF_CONFIG_SMALL("MP4 (MPEG-4 Part 14)"), .mime_type = "application/mp4", .extensions = "mp4", .priv_data_size = sizeof(MOVMuxContext), .audio_codec = CODEC_ID_AAC, -#if CONFIG_LIBX264_ENCODER - .video_codec = CODEC_ID_H264, -#else - .video_codec = CODEC_ID_MPEG4, -#endif + .video_codec = CONFIG_LIBX264_ENCODER ? + CODEC_ID_H264 : CODEC_ID_MPEG4, .write_header = mov_write_header, .write_packet = mov_write_packet, .write_trailer = mov_write_trailer, @@ -3624,15 +3638,12 @@ AVOutputFormat ff_mp4_muxer = { MOV_CLASS(psp) AVOutputFormat ff_psp_muxer = { .name = "psp", - .long_name = NULL_IF_CONFIG_SMALL("PSP MP4 format"), + .long_name = NULL_IF_CONFIG_SMALL("PSP MP4 (MPEG-4 Part 14)"), .extensions = "mp4,psp", .priv_data_size = sizeof(MOVMuxContext), .audio_codec = CODEC_ID_AAC, -#if CONFIG_LIBX264_ENCODER - .video_codec = CODEC_ID_H264, -#else - .video_codec = CODEC_ID_MPEG4, -#endif + .video_codec = CONFIG_LIBX264_ENCODER ? + CODEC_ID_H264 : CODEC_ID_MPEG4, .write_header = mov_write_header, .write_packet = mov_write_packet, .write_trailer = mov_write_trailer, @@ -3645,7 +3656,7 @@ AVOutputFormat ff_psp_muxer = { MOV_CLASS(tg2) AVOutputFormat ff_tg2_muxer = { .name = "3g2", - .long_name = NULL_IF_CONFIG_SMALL("3GP2 format"), + .long_name = NULL_IF_CONFIG_SMALL("3GP2 (3GPP2 file format)"), .extensions = "3g2", .priv_data_size = sizeof(MOVMuxContext), .audio_codec = CODEC_ID_AMR_NB, @@ -3662,7 +3673,7 @@ AVOutputFormat ff_tg2_muxer = { MOV_CLASS(ipod) AVOutputFormat ff_ipod_muxer = { .name = "ipod", - .long_name = NULL_IF_CONFIG_SMALL("iPod H.264 MP4 format"), + .long_name = NULL_IF_CONFIG_SMALL("iPod H.264 MP4 (MPEG-4 Part 14)"), .mime_type = "application/mp4", .extensions = "m4v,m4a", .priv_data_size = sizeof(MOVMuxContext), @@ -3680,7 +3691,7 @@ AVOutputFormat ff_ipod_muxer = { MOV_CLASS(ismv) AVOutputFormat ff_ismv_muxer = { .name = "ismv", - .long_name = NULL_IF_CONFIG_SMALL("ISMV/ISMA (Smooth Streaming) format"), + .long_name = NULL_IF_CONFIG_SMALL("ISMV/ISMA (Smooth Streaming)"), .mime_type = "application/mp4", .extensions = "ismv,isma", .priv_data_size = sizeof(MOVMuxContext),