diff --git a/libavformat/movenc.c b/libavformat/movenc.c index dc5c842cb8..0b44fd66ea 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -142,7 +142,9 @@ static int co64_required(const MOVTrack *track) static int rtp_hinting_needed(const AVStream *st) { - /* Add hint tracks for each audio and video stream */ + /* Add hint tracks for each real audio and video stream */ + if (st->disposition & AV_DISPOSITION_ATTACHED_PIC) + return 0; return st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO || st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO; } @@ -3420,6 +3422,51 @@ static int mov_write_int8_metadata(AVFormatContext *s, AVIOContext *pb, return size; } +static int mov_write_covr(AVIOContext *pb, AVFormatContext *s) +{ + MOVMuxContext *mov = s->priv_data; + int64_t pos = 0; + int i, type; + + for (i = 0; i < s->nb_streams; i++) { + MOVTrack *trk = &mov->tracks[i]; + AVStream *st = s->streams[i]; + + if (!(st->disposition & AV_DISPOSITION_ATTACHED_PIC) || + trk->cover_image.size <= 0) + continue; + + switch (st->codecpar->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_id (0x%x) for cover", + st->codecpar->codec_id); + continue; + } + + if (!pos) { + pos = avio_tell(pb); + avio_wb32(pb, 0); + ffio_wfourcc(pb, "covr"); + } + avio_wb32(pb, 16 + trk->cover_image.size); + ffio_wfourcc(pb, "data"); + avio_wb32(pb, type); + avio_wb32(pb , 0); + avio_write(pb, trk->cover_image.data, trk->cover_image.size); + } + + return pos ? update_size(pb, pos) : 0; +} + /* iTunes meta data list */ static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s) @@ -3454,6 +3501,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); @@ -3951,6 +3999,8 @@ static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov, AVFormat } else { continue; } + if (st->disposition & AV_DISPOSITION_ATTACHED_PIC) + continue; props = (AVCPBProperties*)av_stream_get_side_data(track->st, AV_PKT_DATA_CPB_PROPERTIES, NULL); @@ -4564,6 +4614,8 @@ static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s) for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; + if (st->disposition & AV_DISPOSITION_ATTACHED_PIC) + continue; if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) has_video = 1; if (st->codecpar->codec_id == AV_CODEC_ID_H264) @@ -4712,6 +4764,8 @@ static int mov_write_identification(AVIOContext *pb, AVFormatContext *s) int video_streams_nb = 0, audio_streams_nb = 0, other_streams_nb = 0; for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; + if (st->disposition & AV_DISPOSITION_ATTACHED_PIC) + continue; if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) video_streams_nb++; else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) @@ -4901,7 +4955,8 @@ static int mov_flush_fragment(AVFormatContext *s, int force) int buf_size, moov_size; for (i = 0; i < mov->nb_streams; i++) - if (!mov->tracks[i].entry) + if (!mov->tracks[i].entry && + (i >= s->nb_streams || !(s->streams[i]->disposition & AV_DISPOSITION_ATTACHED_PIC))) break; /* Don't write the initial moov unless all tracks have data */ if (i < mov->nb_streams && !force) @@ -5480,13 +5535,34 @@ static int mov_write_subtitle_end_packet(AVFormatContext *s, static int mov_write_packet(AVFormatContext *s, AVPacket *pkt) { + MOVMuxContext *mov = s->priv_data; + MOVTrack *trk; + AVStream *st; + if (!pkt) { mov_flush_fragment(s, 1); return 1; + } + + st = s->streams[pkt->stream_index]; + trk = &mov->tracks[pkt->stream_index]; + + if (st->disposition & AV_DISPOSITION_ATTACHED_PIC) { + int ret; + + if (st->nb_frames >= 1) { + 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_packet_ref(&trk->cover_image, pkt)) < 0) + return ret; + + return 0; } else { int i; - MOVMuxContext *mov = s->priv_data; - MOVTrack *trk = &mov->tracks[pkt->stream_index]; if (!pkt->size) return mov_write_single_packet(s, pkt); /* Passthrough. */ @@ -5733,7 +5809,8 @@ static void enable_tracks(AVFormatContext *s) AVStream *st = s->streams[i]; if (st->codecpar->codec_type <= AVMEDIA_TYPE_UNKNOWN || - st->codecpar->codec_type >= AVMEDIA_TYPE_NB) + st->codecpar->codec_type >= AVMEDIA_TYPE_NB || + st->disposition & AV_DISPOSITION_ATTACHED_PIC) continue; if (first[st->codecpar->codec_type] < 0) @@ -5776,6 +5853,7 @@ static void mov_free(AVFormatContext *s) av_freep(&mov->tracks[i].par); av_freep(&mov->tracks[i].cluster); av_freep(&mov->tracks[i].frag_info); + av_packet_unref(&mov->tracks[i].cover_image); if (mov->tracks[i].vos_len) av_freep(&mov->tracks[i].vos_data); diff --git a/libavformat/movenc.h b/libavformat/movenc.h index ca2a9c9722..c9b4072fb9 100644 --- a/libavformat/movenc.h +++ b/libavformat/movenc.h @@ -132,6 +132,7 @@ typedef struct MOVTrack { uint32_t default_size; HintSampleQueue sample_queue; + AVPacket cover_image; AVIOContext *mdat_buf; int64_t data_offset;