return 0;
}
+static int rtp_hinting_needed(const AVStream *st)
+{
+ /* 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;
+}
+
/* Chunk offset atom */
static int mov_write_stco_tag(AVIOContext *pb, MOVTrack *track)
{
if (info->num_blocks != 6)
goto end;
av_packet_unref(pkt);
- ret = av_packet_ref(pkt, &info->pkt);
- if (ret < 0)
- goto end;
- av_packet_unref(&info->pkt);
+ av_packet_move_ref(pkt, &info->pkt);
info->num_blocks = 0;
}
ret = pkt->size;
if (ret < 0)
return ret;
- if (mov->mode & MODE_MP4)
+ if (mov->mode & (MODE_MP4|MODE_MOV))
mov_write_track_metadata(pb_buf, st, "name", "title");
if ((size = avio_close_dyn_buf(pb_buf, &buf)) > 0) {
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)
}
mov_write_string_metadata(s, pb, "\251cmt", "comment" , 1);
mov_write_string_metadata(s, pb, "\251gen", "genre" , 1);
- mov_write_string_metadata(s, pb, "\251cpy", "copyright", 1);
+ mov_write_string_metadata(s, pb, "cprt", "copyright", 1);
mov_write_string_metadata(s, pb, "\251grp", "grouping" , 1);
mov_write_string_metadata(s, pb, "\251lyr", "lyrics" , 1);
mov_write_string_metadata(s, pb, "desc", "description",1);
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);
} 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);
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)
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)
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)
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. */
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)
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);
mov->chapter_track = mov->nb_streams++;
if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
- /* Add hint tracks for each audio and video stream */
- for (i = 0; i < s->nb_streams; i++) {
- AVStream *st = s->streams[i];
- if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ||
- st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
+ for (i = 0; i < s->nb_streams; i++)
+ if (rtp_hinting_needed(s->streams[i]))
mov->nb_streams++;
- }
- }
}
if ( mov->write_tmcd == -1 && (mov->mode == MODE_MOV || mov->mode == MODE_MP4)
av_log(s, AV_LOG_ERROR, "VP9 only supported in MP4.\n");
return AVERROR(EINVAL);
}
+ } else if (track->par->codec_id == AV_CODEC_ID_AV1) {
+ /* spec is not finished, so forbid for now */
+ av_log(s, AV_LOG_ERROR, "AV1 muxing is currently not supported.\n");
+ return AVERROR_PATCHWELCOME;
} else if (track->par->codec_id == AV_CODEC_ID_VP8) {
/* altref frames handling is not defined in the spec as of version v1.0,
* so just forbid muxing VP8 streams altogether until a new version does */
nb_tracks++;
if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
- /* Add hint tracks for each audio and video stream */
hint_track = nb_tracks;
- for (i = 0; i < s->nb_streams; i++) {
- AVStream *st = s->streams[i];
- if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ||
- st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
+ for (i = 0; i < s->nb_streams; i++)
+ if (rtp_hinting_needed(s->streams[i]))
nb_tracks++;
- }
- }
}
if (mov->mode == MODE_MOV || mov->mode == MODE_MP4)
return ret;
if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
- /* Initialize the hint tracks for each audio and video stream */
for (i = 0; i < s->nb_streams; i++) {
- AVStream *st = s->streams[i];
- if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ||
- st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
+ if (rtp_hinting_needed(s->streams[i])) {
if ((ret = ff_mov_init_hinting(s, hint_track, i)) < 0)
return ret;
hint_track++;