#include "libavutil/sha.h"
#include "libavutil/timecode.h"
#include "libavcodec/ac3tab.h"
+#include "libavcodec/mpegaudiodecheader.h"
#include "avformat.h"
#include "internal.h"
#include "avio_internal.h"
static void mov_metadata_creation_time(AVDictionary **metadata, int64_t time)
{
- char buffer[32];
if (time) {
- struct tm *ptm, tmbuf;
- time_t timet;
if(time >= 2082844800)
time -= 2082844800; /* seconds between 1904-01-01 and Epoch */
- timet = time;
- ptm = gmtime_r(&timet, &tmbuf);
- if (!ptm) return;
- if (strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", ptm))
- av_dict_set(metadata, "creation_time", buffer, 0);
+ avpriv_dict_set_timestamp(metadata, "creation_time", time * 1000000);
}
}
st->codecpar->color_range = AVCOL_RANGE_JPEG;
else
st->codecpar->color_range = AVCOL_RANGE_MPEG;
- /* 14496-12 references JPEG XR specs (rather than the more complete
- * 23001-8) so some adjusting is required */
- if (color_primaries >= AVCOL_PRI_FILM)
- color_primaries = AVCOL_PRI_UNSPECIFIED;
- if ((color_trc >= AVCOL_TRC_LINEAR &&
- color_trc <= AVCOL_TRC_LOG_SQRT) ||
- color_trc >= AVCOL_TRC_BT2020_10)
- color_trc = AVCOL_TRC_UNSPECIFIED;
- if (color_matrix >= AVCOL_SPC_BT2020_NCL)
- color_matrix = AVCOL_SPC_UNSPECIFIED;
- st->codecpar->color_primaries = color_primaries;
- st->codecpar->color_trc = color_trc;
- st->codecpar->color_space = color_matrix;
- } else if (!strncmp(color_parameter_type, "nclc", 4)) {
- /* color primaries, Table 4-4 */
- switch (color_primaries) {
- case 1: st->codecpar->color_primaries = AVCOL_PRI_BT709; break;
- case 5: st->codecpar->color_primaries = AVCOL_PRI_SMPTE170M; break;
- case 6: st->codecpar->color_primaries = AVCOL_PRI_SMPTE240M; break;
- }
- /* color transfer, Table 4-5 */
- switch (color_trc) {
- case 1: st->codecpar->color_trc = AVCOL_TRC_BT709; break;
- case 7: st->codecpar->color_trc = AVCOL_TRC_SMPTE240M; break;
- }
- /* color matrix, Table 4-6 */
- switch (color_matrix) {
- case 1: st->codecpar->color_space = AVCOL_SPC_BT709; break;
- case 6: st->codecpar->color_space = AVCOL_SPC_BT470BG; break;
- case 7: st->codecpar->color_space = AVCOL_SPC_SMPTE240M; break;
- }
}
+ if (color_primaries >= AVCOL_PRI_NB)
+ color_primaries = AVCOL_PRI_UNSPECIFIED;
+ if (color_trc >= AVCOL_TRC_NB)
+ color_trc = AVCOL_TRC_UNSPECIFIED;
+ if (color_matrix >= AVCOL_SPC_NB)
+ color_matrix = AVCOL_SPC_UNSPECIFIED;
+ st->codecpar->color_primaries = color_primaries;
+ st->codecpar->color_trc = color_trc;
+ st->codecpar->color_space = color_matrix;
av_log(c->fc, AV_LOG_TRACE, "\n");
return 0;
if (codec_tag &&
(codec_tag != format &&
+ // prores is allowed to have differing data format and codec tag
+ codec_tag != AV_RL32("apcn") && codec_tag != AV_RL32("apch") &&
(c->fc->video_codec_id ? video_codec_id != c->fc->video_codec_id
: codec_tag != MKTAG('j','p','e','g')))) {
/* Multiple fourcc, we skip JPEG. This is not correct, we should
avio_skip(pb, size);
return 1;
}
- if ( codec_tag == AV_RL32("avc1") ||
- codec_tag == AV_RL32("hvc1") ||
+ if ( codec_tag == AV_RL32("hvc1") ||
codec_tag == AV_RL32("hev1")
)
av_log(c->fc, AV_LOG_WARNING, "Concatenated H.264 or H.265 might not play correctly.\n");
return ret;
} else if (a.size > 0)
avio_skip(pb, a.size);
+
+ if (sc->extradata) {
+ int extra_size = st->codecpar->extradata_size;
+
+ /* Move the current stream extradata to the stream context one. */
+ sc->extradata_size[pseudo_stream_id] = extra_size;
+ sc->extradata[pseudo_stream_id] = av_malloc(extra_size + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (!sc->extradata[pseudo_stream_id])
+ return AVERROR(ENOMEM);
+ memcpy(sc->extradata[pseudo_stream_id], st->codecpar->extradata, extra_size);
+ av_freep(&st->codecpar->extradata);
+ st->codecpar->extradata_size = 0;
+ }
}
if (pb->eof_reached)
static int mov_read_stsd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
+ AVStream *st;
+ MOVStreamContext *sc;
+ int ret;
int entries;
+ if (c->fc->nb_streams < 1)
+ return 0;
+ st = c->fc->streams[c->fc->nb_streams - 1];
+ sc = st->priv_data;
+
avio_r8(pb); /* version */
avio_rb24(pb); /* flags */
- entries = avio_rb32(pb);
+ entries = avio_rb32(pb); /* entries */
+
+ if (entries <= 0) {
+ av_log(c->fc, AV_LOG_ERROR, "invalid STSD entries %d\n", entries);
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (sc->extradata) {
+ av_log(c->fc, AV_LOG_ERROR, "Duplicate STSD\n");
+ return AVERROR_INVALIDDATA;
+ }
+ /* Prepare space for hosting multiple extradata. */
+ sc->extradata = av_mallocz_array(entries, sizeof(*sc->extradata));
+ sc->extradata_size = av_mallocz_array(entries, sizeof(*sc->extradata_size));
+ if (!sc->extradata_size || !sc->extradata) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ ret = ff_mov_read_stsd_entries(c, pb, entries);
+ if (ret < 0)
+ return ret;
+
+ sc->stsd_count = entries;
+
+ /* Restore back the primary extradata. */
+ av_freep(&st->codecpar->extradata);
+ st->codecpar->extradata_size = sc->extradata_size[0];
+ if (sc->extradata_size[0]) {
+ st->codecpar->extradata = av_mallocz(sc->extradata_size[0] + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (!st->codecpar->extradata)
+ return AVERROR(ENOMEM);
+ memcpy(st->codecpar->extradata, sc->extradata[0], sc->extradata_size[0]);
+ }
- return ff_mov_read_stsd_entries(c, pb, entries);
+ return 0;
+fail:
+ av_freep(&sc->extradata);
+ av_freep(&sc->extradata_size);
+ return ret;
}
static int mov_read_stsc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return 0;
}
+/* Compute the samples value for the stsc entry at the given index. */
+static inline int mov_get_stsc_samples(MOVStreamContext *sc, int index)
+{
+ int chunk_count;
+
+ if (index < sc->stsc_count - 1)
+ chunk_count = sc->stsc_data[index + 1].first - sc->stsc_data[index].first;
+ else
+ chunk_count = sc->chunk_count - (sc->stsc_data[index].first - 1);
+
+ return sc->stsc_data[index].count * chunk_count;
+}
+
static int mov_read_stps(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
AVStream *st;
empty_duration = av_rescale(empty_duration, sc->time_scale, mov->time_scale);
sc->time_offset = start_time - empty_duration;
current_dts = -sc->time_offset;
- if (sc->ctts_count>0 && sc->stts_count>0 &&
- sc->ctts_data[0].duration / FFMAX(sc->stts_data[0].duration, 1) > 16) {
- /* more than 16 frames delay, dts are likely wrong
- this happens with files created by iMovie */
- sc->wrong_dts = 1;
- st->codecpar->video_delay = 1;
- }
}
if (!unsupported && st->codecpar->codec_id == AV_CODEC_ID_AAC && start_time > 0)
}
/* Do not need those anymore. */
av_freep(&sc->chunk_offsets);
- av_freep(&sc->stsc_data);
av_freep(&sc->sample_sizes);
av_freep(&sc->keyframes);
av_freep(&sc->stts_data);
av_freep(&sc->rap_group);
av_freep(&sc->display_matrix);
+ if (sc->extradata)
+ for (j = 0; j < sc->stsd_count; j++)
+ av_free(sc->extradata[j]);
+ av_freep(&sc->extradata);
+ av_freep(&sc->extradata_size);
+
av_freep(&sc->cenc.auxiliary_info);
av_freep(&sc->cenc.auxiliary_info_sizes);
av_aes_ctr_free(sc->cenc.aes_ctr);
return 1;
}
+static int mov_change_extradata(MOVStreamContext *sc, AVPacket *pkt)
+{
+ uint8_t *side, *extradata;
+ int extradata_size;
+
+ /* Save the current index. */
+ sc->last_stsd_index = sc->stsc_data[sc->stsc_index].id - 1;
+
+ /* Notify the decoder that extradata changed. */
+ extradata_size = sc->extradata_size[sc->last_stsd_index];
+ extradata = sc->extradata[sc->last_stsd_index];
+ if (extradata_size > 0 && extradata) {
+ side = av_packet_new_side_data(pkt,
+ AV_PKT_DATA_NEW_EXTRADATA,
+ extradata_size);
+ if (!side)
+ return AVERROR(ENOMEM);
+ memcpy(side, extradata, extradata_size);
+ }
+
+ return 0;
+}
+
static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
{
MOVContext *mov = s->priv_data;
sc->current_sample -= should_retry(sc->pb, ret64);
return AVERROR_INVALIDDATA;
}
+
+ if( st->discard == AVDISCARD_NONKEY && 0==(sample->flags & AVINDEX_KEYFRAME) ) {
+ av_log(mov->fc, AV_LOG_DEBUG, "Nonkey frame from stream %d discarded due to AVDISCARD_NONKEY\n", sc->ffindex);
+ goto retry;
+ }
+
ret = av_get_packet(sc->pb, pkt, sample->size);
if (ret < 0) {
sc->current_sample -= should_retry(sc->pb, ret);
return ret;
}
#endif
+ if (st->codecpar->codec_id == AV_CODEC_ID_MP3 && !st->need_parsing && pkt->size > 4) {
+ if (ff_mpa_check_header(AV_RB32(pkt->data)) < 0)
+ st->need_parsing = AVSTREAM_PARSE_FULL;
+ }
}
pkt->stream_index = sc->ffindex;
sc->ctts_index++;
sc->ctts_sample = 0;
}
- if (sc->wrong_dts)
- pkt->dts = AV_NOPTS_VALUE;
} else {
int64_t next_dts = (sc->current_sample < st->nb_index_entries) ?
st->index_entries[sc->current_sample].timestamp : st->duration;
pkt->flags |= sample->flags & AVINDEX_KEYFRAME ? AV_PKT_FLAG_KEY : 0;
pkt->pos = sample->pos;
+ /* Multiple stsd handling. */
+ if (sc->stsc_data) {
+ /* Keep track of the stsc index for the given sample, then check
+ * if the stsd index is different from the last used one. */
+ sc->stsc_sample++;
+ if (sc->stsc_index < sc->stsc_count - 1 &&
+ mov_get_stsc_samples(sc, sc->stsc_index) == sc->stsc_sample) {
+ sc->stsc_index++;
+ sc->stsc_sample = 0;
+ /* Do not check indexes after a switch. */
+ } else if (sc->stsc_data[sc->stsc_index].id > 0 &&
+ sc->stsc_data[sc->stsc_index].id - 1 < sc->stsd_count &&
+ sc->stsc_data[sc->stsc_index].id - 1 != sc->last_stsd_index) {
+ ret = mov_change_extradata(sc, pkt);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
if (mov->aax_mode)
aax_filter(pkt->data, pkt->size, mov);
}
}
+ /* adjust stsd index */
+ time_sample = 0;
+ for (i = 0; i < sc->stsc_count; i++) {
+ int next = time_sample + mov_get_stsc_samples(sc, i);
+ if (next > sc->current_sample) {
+ sc->stsc_index = i;
+ sc->stsc_sample = sc->current_sample - time_sample;
+ break;
+ }
+ time_sample = next;
+ }
+
ret = mov_seek_auxiliary_info(s, sc);
if (ret < 0) {
return ret;