Fixes https://trac.ffmpeg.org/ticket/2798
This makes movenc handle AV_DISPOSITION_ATTACHED_PIC and write the associated pictures in iTunes cover atom. This corresponds to how 'mov' demuxer parses and exposes the cover images when reading. Tested to produce valid stream with: ffmpeg -i movie.mp4 -i thumb.jpg -disposition:v:1 attached_pic -map 0 -map 1 -c copy out.mp4 The cover image is also copied corretly with: ffmpeg -i movie.mp4 -map 0 -c copy out.mp4 AtomicParseley says that the attached_pic stream is properly not visible in the main tracks of the file. Though, I am not sure if there's any side-effects of having internal stream without any packets. We may need to arm the mov muxer with additional checks for streams without any packets. It may make sense to move the code in mov_write_packet() that grabs the attached picture to generic code in mux.c. Seems there's currently no other muxer supporting cover images than mp3 and it seems to use special code to handle them. Signed-off-by: Timo Teräs <timo.te...@iki.fi> Cc: Matthieu Bouron <matthieu.bou...@gmail.com> --- fftools/ffmpeg.c | 1 + libavformat/movenc.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 1b2e37b8d8..b6751d7faa 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -3562,6 +3562,7 @@ static int init_output_stream(OutputStream *ost, char *error, int error_len) { "hearing_impaired" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_HEARING_IMPAIRED }, .unit = "flags" }, { "visual_impaired" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_VISUAL_IMPAIRED }, .unit = "flags" }, { "clean_effects" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_CLEAN_EFFECTS }, .unit = "flags" }, + { "attached_pic" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_ATTACHED_PIC }, .unit = "flags" }, { "captions" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_CAPTIONS }, .unit = "flags" }, { "descriptions" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_DESCRIPTIONS }, .unit = "flags" }, { "dependent" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_DEPENDENT }, .unit = "flags" }, diff --git a/libavformat/movenc.c b/libavformat/movenc.c index 230aeb6a6d..5400b2747e 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -3414,6 +3414,54 @@ static int mov_write_int8_metadata(AVFormatContext *s, AVIOContext *pb, return size; } +static int mov_write_covr(AVIOContext *pb, AVFormatContext *s) +{ + int64_t pos = 0; + int i; + + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; + enum AVCodecID codec_id = st->codecpar->codec_id; + int type; + + if (!(st->disposition & AV_DISPOSITION_ATTACHED_PIC)) + continue; + + switch (codec_id) { + case AV_CODEC_ID_MJPEG: + type = 0xD; + break; + case AV_CODEC_ID_PNG: + type = 0xE; + break; + case AV_CODEC_ID_BMP: + type = 0x1B; + break; + default: + av_log(s, AV_LOG_ERROR, "unsupported codec %s for cover, skipping", + av_fourcc2str(st->codecpar->codec_tag)); + continue; + } + + if (!pos) { + pos = avio_tell(pb); + avio_wb32(pb, 0); + ffio_wfourcc(pb, "covr"); + } + + avio_wb32(pb, 16 + st->attached_pic.size); + ffio_wfourcc(pb, "data"); + avio_wb32(pb, type); + avio_wb32(pb , 0); + avio_write(pb, st->attached_pic.data, st->attached_pic.size); + } + + if (pos) + return update_size(pb, pos); + + return 0; +} + /* iTunes meta data list */ static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s) @@ -3451,6 +3499,7 @@ static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov, mov_write_int8_metadata (s, pb, "hdvd", "hd_video", 1); mov_write_int8_metadata (s, pb, "pgap", "gapless_playback",1); mov_write_int8_metadata (s, pb, "cpil", "compilation", 1); + mov_write_covr(pb, s); mov_write_trkn_tag(pb, mov, s, 0); // track number mov_write_trkn_tag(pb, mov, s, 1); // disc number mov_write_tmpo_tag(pb, s); @@ -5480,6 +5529,24 @@ static int mov_write_packet(AVFormatContext *s, AVPacket *pkt) if (!pkt) { mov_flush_fragment(s, 1); return 1; + } if (s->streams[pkt->stream_index]->disposition & AV_DISPOSITION_ATTACHED_PIC) { + AVStream *st = s->streams[pkt->stream_index]; + int ret; + + if (st->nb_frames >= 1) { + /* warn only once */ + if (st->nb_frames == 1) + av_log(s, AV_LOG_WARNING, "Got more than one picture in stream %d," + " ignoring.\n", pkt->stream_index); + return 0; + } + + if ((ret = av_copy_packet(&st->attached_pic, pkt)) < 0) + return ret; + + st->attached_pic.stream_index = st->index; + st->attached_pic.flags |= AV_PKT_FLAG_KEY; + return 0; } else { int i; MOVMuxContext *mov = s->priv_data; -- 2.16.2 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel