Commit message: avformat/mov: Check count sums in build_open_gop_key_points()

Fixes: ffmpeg.md
Fixes: Out of array access
Fixes: CVE-2022-2566

Found-by: Andy Nguyen <theflow@google.com>
Found-by: 3pvd <3pvd@google.com>
Reviewed-by: Andy Nguyen <theflow@google.com>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
CVE: None
CWE: CWE-703
Vulnerability description: None

Project: FFmpeg
File: mov.c

static int mov_read_colr(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
    AVStream *st;
    uint8_t *icc_profile;
    char color_parameter_type[5] = { 0 };
    uint16_t color_primaries, color_trc, color_matrix;
    int ret;

    if (c->fc->nb_streams < 1)
        return 0;
    st = c->fc->streams[c->fc->nb_streams - 1];

    ret = ffio_read_size(pb, color_parameter_type, 4);
    if (ret < 0)
        return ret;
    if (strncmp(color_parameter_type, "nclx", 4) &&
        strncmp(color_parameter_type, "nclc", 4) &&
        strncmp(color_parameter_type, "prof", 4)) {
        av_log(c->fc, AV_LOG_WARNING, "unsupported color_parameter_type %s\n",
               color_parameter_type);
        return 0;
    }

    if (!strncmp(color_parameter_type, "prof", 4)) {
        icc_profile = av_stream_new_side_data(st, AV_PKT_DATA_ICC_PROFILE, atom.size - 4);
        if (!icc_profile)
            return AVERROR(ENOMEM);
        ret = ffio_read_size(pb, icc_profile, atom.size - 4);
        if (ret < 0)
            return ret;
    } else {
        color_primaries = avio_rb16(pb);
        color_trc = avio_rb16(pb);
        color_matrix = avio_rb16(pb);

        av_log(c->fc, AV_LOG_TRACE,
               "%s: pri %d trc %d matrix %d",
               color_parameter_type, color_primaries, color_trc, color_matrix);

        if (!strncmp(color_parameter_type, "nclx", 4)) {
            uint8_t color_range = avio_r8(pb) >> 7;
            av_log(c->fc, AV_LOG_TRACE, " full %"PRIu8"", color_range);
            if (color_range)
                st->codecpar->color_range = AVCOL_RANGE_JPEG;
            else
                st->codecpar->color_range = AVCOL_RANGE_MPEG;
        }

        if (!av_color_primaries_name(color_primaries))
            color_primaries = AVCOL_PRI_UNSPECIFIED;
        if (!av_color_transfer_name(color_trc))
            color_trc = AVCOL_TRC_UNSPECIFIED;
        if (!av_color_space_name(color_matrix))
            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;
}

Project: FFmpeg
File: mov.c

static int search_frag_timestamp(AVFormatContext *s, MOVFragmentIndex *frag_index,
                                 AVStream *st, int64_t timestamp)
{
    int a, b, m, m0;
    int64_t frag_time;

    a = -1;
    b = frag_index->nb_items;

    while (b - a > 1) {
        m0 = m = (a + b) >> 1;

        while (m < b &&
               (frag_time = get_frag_time(s, st, frag_index, m)) == AV_NOPTS_VALUE)
            m++;

        if (m < b && frag_time <= timestamp)
            a = m;
        else
            b = m0;
    }

    return a;
}

Project: FFmpeg
File: mov.c

static int mov_metadata_loci(MOVContext *c, AVIOContext *pb, unsigned len)
{
    char language[4] = { 0 };
    char buf[200], place[100];
    uint16_t langcode = 0;
    double longitude, latitude, altitude;
    const char *key = "location";

    if (len < 4 + 2 + 1 + 1 + 4 + 4 + 4) {
        av_log(c->fc, AV_LOG_ERROR, "loci too short\n");
        return AVERROR_INVALIDDATA;
    }

    avio_skip(pb, 4); // version+flags
    langcode = avio_rb16(pb);
    ff_mov_lang_to_iso639(langcode, language);
    len -= 6;

    len -= avio_get_str(pb, len, place, sizeof(place));
    if (len < 1) {
        av_log(c->fc, AV_LOG_ERROR, "place name too long\n");
        return AVERROR_INVALIDDATA;
    }
    avio_skip(pb, 1); // role
    len -= 1;

    if (len < 12) {
        av_log(c->fc, AV_LOG_ERROR,
               "loci too short (%u bytes left, need at least %d)\n", len, 12);
        return AVERROR_INVALIDDATA;
    }
    longitude = ((int32_t) avio_rb32(pb)) / (float) (1 << 16);
    latitude  = ((int32_t) avio_rb32(pb)) / (float) (1 << 16);
    altitude  = ((int32_t) avio_rb32(pb)) / (float) (1 << 16);

    // Try to output in the same format as the ?xyz field
    snprintf(buf, sizeof(buf), "%+08.4f%+09.4f",  latitude, longitude);
    if (altitude)
        av_strlcatf(buf, sizeof(buf), "%+f", altitude);
    av_strlcatf(buf, sizeof(buf), "/%s", place);

    if (*language && strcmp(language, "und")) {
        char key2[16];
        snprintf(key2, sizeof(key2), "%s-%s", key, language);
        av_dict_set(&c->fc->metadata, key2, buf, 0);
    }
    c->fc->event_flags |= AVFMT_EVENT_FLAG_METADATA_UPDATED;
    return av_dict_set(&c->fc->metadata, key, buf, 0);
}

Project: FFmpeg
File: mov.c

static int mov_read_chap(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
    unsigned i, num;
    void *new_tracks;

    num = atom.size / 4;
    if (!(new_tracks = av_malloc_array(num, sizeof(int))))
        return AVERROR(ENOMEM);

    av_free(c->chapter_tracks);
    c->chapter_tracks = new_tracks;
    c->nb_chapter_tracks = num;

    for (i = 0; i < num && !pb->eof_reached; i++)
        c->chapter_tracks[i] = avio_rb32(pb);

    c->nb_chapter_tracks = i;

    return 0;
}

Project: FFmpeg
File: mov.c

static int mov_read_SA3D(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
    AVStream *st;
    int i, version, type;
    int ambisonic_order, channel_order, normalization, channel_count;

    if (c->fc->nb_streams < 1)
        return 0;

    st = c->fc->streams[c->fc->nb_streams - 1];

    if (atom.size < 16) {
        av_log(c->fc, AV_LOG_ERROR, "SA3D audio box too small\n");
        return AVERROR_INVALIDDATA;
    }

    version = avio_r8(pb);
    if (version) {
        av_log(c->fc, AV_LOG_WARNING, "Unsupported SA3D box version %d\n", version);
        return 0;
    }

    type = avio_r8(pb);
    if (type) {
        av_log(c->fc, AV_LOG_WARNING,
               "Unsupported ambisonic type %d\n", type);
        return 0;
    }

    ambisonic_order = avio_rb32(pb);

    channel_order = avio_r8(pb);
    if (channel_order) {
        av_log(c->fc, AV_LOG_WARNING,
               "Unsupported channel_order %d\n", channel_order);
        return 0;
    }

    normalization = avio_r8(pb);
    if (normalization) {
        av_log(c->fc, AV_LOG_WARNING,
               "Unsupported normalization %d\n", normalization);
        return 0;
    }

    channel_count = avio_rb32(pb);
    if (ambisonic_order < 0 || channel_count != (ambisonic_order + 1LL) * (ambisonic_order + 1LL)) {
        av_log(c->fc, AV_LOG_ERROR,
               "Invalid number of channels (%d / %d)\n",
               channel_count, ambisonic_order);
        return 0;
    }

    for (i = 0; i < channel_count; i++) {
        if (i != avio_rb32(pb)) {
            av_log(c->fc, AV_LOG_WARNING,
                   "Ambisonic channel reordering is not supported\n");
            return 0;
        }
    }

    av_channel_layout_uninit(&st->codecpar->ch_layout);
    st->codecpar->ch_layout.order = AV_CHANNEL_ORDER_AMBISONIC;
    st->codecpar->ch_layout.nb_channels = channel_count;

    return 0;
}

Project: FFmpeg
File: mov.c

static int mov_switch_root(AVFormatContext *s, int64_t target, int index)
{
    int ret;
    MOVContext *mov = s->priv_data;

    if (index >= 0 && index < mov->frag_index.nb_items)
        target = mov->frag_index.item[index].moof_offset;
    if (avio_seek(s->pb, target, SEEK_SET) != target) {
        av_log(mov->fc, AV_LOG_ERROR, "root atom offset 0x%"PRIx64": partial file\n", target);
        return AVERROR_INVALIDDATA;
    }

    mov->next_root_atom = 0;
    if (index < 0 || index >= mov->frag_index.nb_items)
        index = search_frag_moof_offset(&mov->frag_index, target);
    if (index < mov->frag_index.nb_items &&
        mov->frag_index.item[index].moof_offset == target) {
        if (index + 1 < mov->frag_index.nb_items)
            mov->next_root_atom = mov->frag_index.item[index + 1].moof_offset;
        if (mov->frag_index.item[index].headers_read)
            return 0;
        mov->frag_index.item[index].headers_read = 1;
    }

    mov->found_mdat = 0;

    ret = mov_read_default(mov, s->pb, (MOVAtom){ AV_RL32("root"), INT64_MAX });
    if (ret < 0)
        return ret;
    if (avio_feof(s->pb))
        return AVERROR_EOF;
    av_log(s, AV_LOG_TRACE, "read fragments, offset 0x%"PRIx64"\n", avio_tell(s->pb));

    return 1;
}

Project: FFmpeg
File: mov.c

static void mov_read_chapters(AVFormatContext *s)
{
    MOVContext *mov = s->priv_data;
    MOVStreamContext *sc;
    int64_t cur_pos;
    int i, j;
    int chapter_track;

    for (j = 0; j < mov->nb_chapter_tracks; j++) {
        AVStream *st = NULL;
        FFStream *sti = NULL;
        chapter_track = mov->chapter_tracks[j];
        for (i = 0; i < s->nb_streams; i++)
            if (s->streams[i]->id == chapter_track) {
                st = s->streams[i];
                break;
            }
        if (!st) {
            av_log(s, AV_LOG_ERROR, "Referenced QT chapter track not found\n");
            continue;
        }
        sti = ffstream(st);

        sc = st->priv_data;
        cur_pos = avio_tell(sc->pb);

        if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
            st->disposition |= AV_DISPOSITION_ATTACHED_PIC | AV_DISPOSITION_TIMED_THUMBNAILS;
            if (sti->nb_index_entries) {
                // Retrieve the first frame, if possible
                AVIndexEntry *sample = &sti->index_entries[0];
                if (avio_seek(sc->pb, sample->pos, SEEK_SET) != sample->pos) {
                    av_log(s, AV_LOG_ERROR, "Failed to retrieve first frame\n");
                    goto finish;
                }

                if (ff_add_attached_pic(s, st, sc->pb, NULL, sample->size) < 0)
                    goto finish;
            }
        } else {
            st->codecpar->codec_type = AVMEDIA_TYPE_DATA;
            st->codecpar->codec_id = AV_CODEC_ID_BIN_DATA;
            st->discard = AVDISCARD_ALL;
            for (int i = 0; i < sti->nb_index_entries; i++) {
                AVIndexEntry *sample = &sti->index_entries[i];
                int64_t end = i+1 < sti->nb_index_entries ? sti->index_entries[i+1].timestamp : st->duration;
                uint8_t *title;
                uint16_t ch;
                int len, title_len;

                if (end < sample->timestamp) {
                    av_log(s, AV_LOG_WARNING, "ignoring stream duration which is shorter than chapters\n");
                    end = AV_NOPTS_VALUE;
                }

                if (avio_seek(sc->pb, sample->pos, SEEK_SET) != sample->pos) {
                    av_log(s, AV_LOG_ERROR, "Chapter %d not found in file\n", i);
                    goto finish;
                }

                // the first two bytes are the length of the title
                len = avio_rb16(sc->pb);
                if (len > sample->size-2)
                    continue;
                title_len = 2*len + 1;
                if (!(title = av_mallocz(title_len)))
                    goto finish;

                // The samples could theoretically be in any encoding if there's an encd
                // atom following, but in practice are only utf-8 or utf-16, distinguished
                // instead by the presence of a BOM
                if (!len) {
                    title[0] = 0;
                } else {
                    ch = avio_rb16(sc->pb);
                    if (ch == 0xfeff)
                        avio_get_str16be(sc->pb, len, title, title_len);
                    else if (ch == 0xfffe)
                        avio_get_str16le(sc->pb, len, title, title_len);
                    else {
                        AV_WB16(title, ch);
                        if (len == 1 || len == 2)
                            title[len] = 0;
                        else
                            avio_get_str(sc->pb, INT_MAX, title + 2, len - 1);
                    }
                }

                avpriv_new_chapter(s, i, st->time_base, sample->timestamp, end, title);
                av_freep(&title);
            }
        }
finish:
        avio_seek(sc->pb, cur_pos, SEEK_SET);
    }
}

Project: FFmpeg
File: mov.c

static int mov_parse_auxiliary_info(MOVContext *c, MOVStreamContext *sc, AVIOContext *pb, MOVEncryptionIndex *encryption_index)
{
    AVEncryptionInfo **sample, **encrypted_samples;
    int64_t prev_pos;
    size_t sample_count, sample_info_size, i;
    int ret = 0;
    unsigned int alloc_size = 0;

    if (encryption_index->nb_encrypted_samples)
        return 0;
    sample_count = encryption_index->auxiliary_info_sample_count;
    if (encryption_index->auxiliary_offsets_count != 1) {
        av_log(c->fc, AV_LOG_ERROR, "Multiple auxiliary info chunks are not supported\n");
        return AVERROR_PATCHWELCOME;
    }
    if (sample_count >= INT_MAX / sizeof(*encrypted_samples))
        return AVERROR(ENOMEM);

    prev_pos = avio_tell(pb);
    if (!(pb->seekable & AVIO_SEEKABLE_NORMAL) ||
        avio_seek(pb, encryption_index->auxiliary_offsets[0], SEEK_SET) != encryption_index->auxiliary_offsets[0]) {
        av_log(c->fc, AV_LOG_INFO, "Failed to seek for auxiliary info, will only parse senc atoms for encryption info\n");
        goto finish;
    }

    for (i = 0; i < sample_count && !pb->eof_reached; i++) {
        unsigned int min_samples = FFMIN(FFMAX(i + 1, 1024 * 1024), sample_count);
        encrypted_samples = av_fast_realloc(encryption_index->encrypted_samples, &alloc_size,
                                            min_samples * sizeof(*encrypted_samples));
        if (!encrypted_samples) {
            ret = AVERROR(ENOMEM);
            goto finish;
        }
        encryption_index->encrypted_samples = encrypted_samples;

        sample = &encryption_index->encrypted_samples[i];
        sample_info_size = encryption_index->auxiliary_info_default_size
                               ? encryption_index->auxiliary_info_default_size
                               : encryption_index->auxiliary_info_sizes[i];

        ret = mov_read_sample_encryption_info(c, pb, sc, sample, sample_info_size > sc->cenc.per_sample_iv_size);
        if (ret < 0)
            goto finish;
    }
    if (pb->eof_reached) {
        av_log(c->fc, AV_LOG_ERROR, "Hit EOF while reading auxiliary info\n");
        ret = AVERROR_INVALIDDATA;
    } else {
        encryption_index->nb_encrypted_samples = sample_count;
    }

finish:
    avio_seek(pb, prev_pos, SEEK_SET);
    if (ret < 0) {
        for (; i > 0; i--) {
            av_encryption_info_free(encryption_index->encrypted_samples[i - 1]);
        }
        av_freep(&encryption_index->encrypted_samples);
    }
    return ret;
}

Project: FFmpeg
File: mov.c

static int cbc1_scheme_decrypt(MOVContext *c, MOVStreamContext *sc, AVEncryptionInfo *sample, uint8_t *input, int size)
{
    int i, ret;
    int num_of_encrypted_blocks;
    uint8_t iv[16];

    if (!sc->cenc.aes_ctx) {
        /* initialize the cipher */
        sc->cenc.aes_ctx = av_aes_alloc();
        if (!sc->cenc.aes_ctx) {
            return AVERROR(ENOMEM);
        }

        ret = av_aes_init(sc->cenc.aes_ctx, c->decryption_key, 16 * 8, 1);
        if (ret < 0) {
            return ret;
        }
    }

    memcpy(iv, sample->iv, 16);

    /* whole-block full sample encryption */
    if (!sample->subsample_count) {
        /* decrypt the whole packet */
        av_aes_crypt(sc->cenc.aes_ctx, input, input, size/16, iv, 1);
        return 0;
    }

    for (i = 0; i < sample->subsample_count; i++) {
        if (sample->subsamples[i].bytes_of_clear_data + sample->subsamples[i].bytes_of_protected_data > size) {
            av_log(c->fc, AV_LOG_ERROR, "subsample size exceeds the packet size left\n");
            return AVERROR_INVALIDDATA;
        }

        if (sample->subsamples[i].bytes_of_protected_data % 16) {
            av_log(c->fc, AV_LOG_ERROR, "subsample BytesOfProtectedData is not a multiple of 16\n");
            return AVERROR_INVALIDDATA;
        }

        /* skip the clear bytes */
        input += sample->subsamples[i].bytes_of_clear_data;
        size -= sample->subsamples[i].bytes_of_clear_data;

        /* decrypt the encrypted bytes */
        num_of_encrypted_blocks = sample->subsamples[i].bytes_of_protected_data/16;
        if (num_of_encrypted_blocks > 0) {
            av_aes_crypt(sc->cenc.aes_ctx, input, input, num_of_encrypted_blocks, iv, 1);
        }
        input += sample->subsamples[i].bytes_of_protected_data;
        size -= sample->subsamples[i].bytes_of_protected_data;
    }

    if (size > 0) {
        av_log(c->fc, AV_LOG_ERROR, "leftover packet bytes after subsample processing\n");
        return AVERROR_INVALIDDATA;
    }

    return 0;
}

Project: FFmpeg
File: mov.c

static int64_t add_index_entry(AVStream *st, int64_t pos, int64_t timestamp,
                               int size, int distance, int flags)
{
    FFStream *const sti = ffstream(st);
    AVIndexEntry *entries, *ie;
    int64_t index = -1;
    const size_t min_size_needed = (sti->nb_index_entries + 1) * sizeof(AVIndexEntry);

    // Double the allocation each time, to lower memory fragmentation.
    // Another difference from ff_add_index_entry function.
    const size_t requested_size =
        min_size_needed > sti->index_entries_allocated_size ?
        FFMAX(min_size_needed, 2 * sti->index_entries_allocated_size) :
        min_size_needed;

    if (sti->nb_index_entries + 1U >= UINT_MAX / sizeof(AVIndexEntry))
        return -1;

    entries = av_fast_realloc(sti->index_entries,
                              &sti->index_entries_allocated_size,
                              requested_size);
    if (!entries)
        return -1;

    sti->index_entries = entries;

    index = sti->nb_index_entries++;
    ie= &entries[index];

    ie->pos = pos;
    ie->timestamp = timestamp;
    ie->min_distance= distance;
    ie->size= size;
    ie->flags = flags;
    return index;
}

Project: FFmpeg
File: mov.c

static int mov_read_tkhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
    int i, j, e;
    int width;
    int height;
    int display_matrix[3][3];
    int res_display_matrix[3][3] = { { 0 } };
    AVStream *st;
    MOVStreamContext *sc;
    int version;
    int flags;

    if (c->fc->nb_streams < 1)
        return 0;
    st = c->fc->streams[c->fc->nb_streams-1];
    sc = st->priv_data;

    // Each stream (trak) should have exactly 1 tkhd. This catches bad files and
    // avoids corrupting AVStreams mapped to an earlier tkhd.
    if (st->id != -1)
        return AVERROR_INVALIDDATA;

    version = avio_r8(pb);
    flags = avio_rb24(pb);
    st->disposition |= (flags & MOV_TKHD_FLAG_ENABLED) ? AV_DISPOSITION_DEFAULT : 0;

    if (version == 1) {
        avio_rb64(pb);
        avio_rb64(pb);
    } else {
        avio_rb32(pb); /* creation time */
        avio_rb32(pb); /* modification time */
    }
    st->id = (int)avio_rb32(pb); /* track id (NOT 0 !)*/
    avio_rb32(pb); /* reserved */

    /* highlevel (considering edits) duration in movie timebase */
    (version == 1) ? avio_rb64(pb) : avio_rb32(pb);
    avio_rb32(pb); /* reserved */
    avio_rb32(pb); /* reserved */

    avio_rb16(pb); /* layer */
    avio_rb16(pb); /* alternate group */
    avio_rb16(pb); /* volume */
    avio_rb16(pb); /* reserved */

    //read in the display matrix (outlined in ISO 14496-12, Section 6.2.2)
    // they're kept in fixed point format through all calculations
    // save u,v,z to store the whole matrix in the AV_PKT_DATA_DISPLAYMATRIX
    // side data, but the scale factor is not needed to calculate aspect ratio
    for (i = 0; i < 3; i++) {
        display_matrix[i][0] = avio_rb32(pb);   // 16.16 fixed point
        display_matrix[i][1] = avio_rb32(pb);   // 16.16 fixed point
        display_matrix[i][2] = avio_rb32(pb);   //  2.30 fixed point
    }

    width = avio_rb32(pb);       // 16.16 fixed point track width
    height = avio_rb32(pb);      // 16.16 fixed point track height
    sc->width = width >> 16;
    sc->height = height >> 16;

    // apply the moov display matrix (after the tkhd one)
    for (i = 0; i < 3; i++) {
        const int sh[3] = { 16, 16, 30 };
        for (j = 0; j < 3; j++) {
            for (e = 0; e < 3; e++) {
                res_display_matrix[i][j] +=
                    ((int64_t) display_matrix[i][e] *
                     c->movie_display_matrix[e][j]) >> sh[e];
            }
        }
    }

    // save the matrix when it is not the default identity
    if (!IS_MATRIX_IDENT(res_display_matrix)) {
        av_freep(&sc->display_matrix);
        sc->display_matrix = av_malloc(sizeof(int32_t) * 9);
        if (!sc->display_matrix)
            return AVERROR(ENOMEM);

        for (i = 0; i < 3; i++)
            for (j = 0; j < 3; j++)
                sc->display_matrix[i * 3 + j] = res_display_matrix[i][j];
    }

    // transform the display width/height according to the matrix
    // to keep the same scale, use [width height 1<<16]
    if (width && height && sc->display_matrix) {
        double disp_transform[2];

        for (i = 0; i < 2; i++)
            disp_transform[i] = hypot(sc->display_matrix[0 + i],
                                      sc->display_matrix[3 + i]);

        if (disp_transform[0] > 1       && disp_transform[1] > 1 &&
            disp_transform[0] < (1<<24) && disp_transform[1] < (1<<24) &&
            fabs((disp_transform[0] / disp_transform[1]) - 1.0) > 0.01)
            st->sample_aspect_ratio = av_d2q(
                disp_transform[0] / disp_transform[1],
                INT_MAX);
    }
    return 0;
}

Project: FFmpeg
File: mov.c

static inline int64_t mov_get_stsc_samples(MOVStreamContext *sc, unsigned int index)
{
    int chunk_count;

    if (mov_stsc_index_valid(index, sc->stsc_count))
        chunk_count = sc->stsc_data[index + 1].first - sc->stsc_data[index].first;
    else {
        // Validation for stsc / stco  happens earlier in mov_read_stsc + mov_read_trak.
        av_assert0(sc->stsc_data[index].first <= sc->chunk_count);
        chunk_count = sc->chunk_count - (sc->stsc_data[index].first - 1);
    }

    return sc->stsc_data[index].count * (int64_t)chunk_count;
}

Project: FFmpeg
File: mov.c

static int mov_read_wave(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
    AVStream *st;
    int ret;

    if (c->fc->nb_streams < 1)
        return 0;
    st = c->fc->streams[c->fc->nb_streams-1];

    if ((uint64_t)atom.size > (1<<30))
        return AVERROR_INVALIDDATA;

    if (st->codecpar->codec_id == AV_CODEC_ID_QDM2 ||
        st->codecpar->codec_id == AV_CODEC_ID_QDMC ||
        st->codecpar->codec_id == AV_CODEC_ID_SPEEX) {
        // pass all frma atom to codec, needed at least for QDMC and QDM2
        ret = ff_get_extradata(c->fc, st->codecpar, pb, atom.size);
        if (ret < 0)
            return ret;
    } else if (atom.size > 8) { /* to read frma, esds atoms */
        if (st->codecpar->codec_id == AV_CODEC_ID_ALAC && atom.size >= 24) {
            uint64_t buffer;
            ret = ffio_ensure_seekback(pb, 8);
            if (ret < 0)
                return ret;
            buffer = avio_rb64(pb);
            atom.size -= 8;
            if (  (buffer & 0xFFFFFFFF) == MKBETAG('f','r','m','a')
                && buffer >> 32 <= atom.size
                && buffer >> 32 >= 8) {
                avio_skip(pb, -8);
                atom.size += 8;
            } else if (!st->codecpar->extradata_size) {
#define ALAC_EXTRADATA_SIZE 36
                st->codecpar->extradata = av_mallocz(ALAC_EXTRADATA_SIZE + AV_INPUT_BUFFER_PADDING_SIZE);
                if (!st->codecpar->extradata)
                    return AVERROR(ENOMEM);
                st->codecpar->extradata_size = ALAC_EXTRADATA_SIZE;
                AV_WB32(st->codecpar->extradata    , ALAC_EXTRADATA_SIZE);
                AV_WB32(st->codecpar->extradata + 4, MKTAG('a','l','a','c'));
                AV_WB64(st->codecpar->extradata + 12, buffer);
                avio_read(pb, st->codecpar->extradata + 20, 16);
                avio_skip(pb, atom.size - 24);
                return 0;
            }
        }
        if ((ret = mov_read_default(c, pb, atom)) < 0)
            return ret;
    } else
        avio_skip(pb, atom.size);
    return 0;
}

Project: FFmpeg
File: mov.c

static int64_t get_frag_time(AVFormatContext *s, AVStream *dst_st,
                             MOVFragmentIndex *frag_index, int index)
{
    MOVFragmentStreamInfo * frag_stream_info;
    MOVStreamContext *sc = dst_st->priv_data;
    int64_t timestamp;
    int i, j;

    // If the stream is referenced by any sidx, limit the search
    // to fragments that referenced this stream in the sidx
    if (sc->has_sidx) {
        frag_stream_info = get_frag_stream_info(frag_index, index, dst_st->id);
        if (frag_stream_info->sidx_pts != AV_NOPTS_VALUE)
            return frag_stream_info->sidx_pts;
        if (frag_stream_info->first_tfra_pts != AV_NOPTS_VALUE)
            return frag_stream_info->first_tfra_pts;
        return frag_stream_info->sidx_pts;
    }

    for (i = 0; i < frag_index->item[index].nb_stream_info; i++) {
        AVStream *frag_stream = NULL;
        frag_stream_info = &frag_index->item[index].stream_info[i];
        for (j = 0; j < s->nb_streams; j++)
            if (s->streams[j]->id == frag_stream_info->id)
                frag_stream = s->streams[j];
        if (!frag_stream) {
            av_log(s, AV_LOG_WARNING, "No stream matching sidx ID found.\n");
            continue;
        }
        timestamp = get_stream_info_time(frag_stream_info);
        if (timestamp != AV_NOPTS_VALUE)
            return av_rescale_q(timestamp, frag_stream->time_base, dst_st->time_base);
    }
    return AV_NOPTS_VALUE;
}

Project: FFmpeg
File: mov.c

static AVIndexEntry *mov_find_next_sample(AVFormatContext *s, AVStream **st)
{
    AVIndexEntry *sample = NULL;
    int64_t best_dts = INT64_MAX;
    int i;
    for (i = 0; i < s->nb_streams; i++) {
        AVStream *avst = s->streams[i];
        FFStream *const avsti = ffstream(avst);
        MOVStreamContext *msc = avst->priv_data;
        if (msc->pb && msc->current_sample < avsti->nb_index_entries) {
            AVIndexEntry *current_sample = &avsti->index_entries[msc->current_sample];
            int64_t dts = av_rescale(current_sample->timestamp, AV_TIME_BASE, msc->time_scale);
            av_log(s, AV_LOG_TRACE, "stream %d, sample %d, dts %"PRId64"\n", i, msc->current_sample, dts);
            if (!sample || (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL) && current_sample->pos < sample->pos) ||
                ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) &&
                 ((msc->pb != s->pb && dts < best_dts) || (msc->pb == s->pb && dts != AV_NOPTS_VALUE &&
                 ((FFABS(best_dts - dts) <= AV_TIME_BASE && current_sample->pos < sample->pos) ||
                  (FFABS(best_dts - dts) > AV_TIME_BASE && dts < best_dts)))))) {
                sample = current_sample;
                best_dts = dts;
                *st = avst;
            }
        }
    }
    return sample;
}

Project: FFmpeg
File: mov.c

static int64_t get_stream_info_time(MOVFragmentStreamInfo * frag_stream_info)
{
    av_assert0(frag_stream_info);
    if (frag_stream_info->sidx_pts != AV_NOPTS_VALUE)
        return frag_stream_info->sidx_pts;
    if (frag_stream_info->first_tfra_pts != AV_NOPTS_VALUE)
        return frag_stream_info->first_tfra_pts;
    return frag_stream_info->tfdt_dts;
}

Project: FFmpeg
File: mov.c

static int mov_read_cmov(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
#if CONFIG_ZLIB
    FFIOContext ctx;
    uint8_t *cmov_data;
    uint8_t *moov_data; /* uncompressed data */
    long cmov_len, moov_len;
    int ret = -1;

    avio_rb32(pb); /* dcom atom */
    if (avio_rl32(pb) != MKTAG('d','c','o','m'))
        return AVERROR_INVALIDDATA;
    if (avio_rl32(pb) != MKTAG('z','l','i','b')) {
        av_log(c->fc, AV_LOG_ERROR, "unknown compression for cmov atom !\n");
        return AVERROR_INVALIDDATA;
    }
    avio_rb32(pb); /* cmvd atom */
    if (avio_rl32(pb) != MKTAG('c','m','v','d'))
        return AVERROR_INVALIDDATA;
    moov_len = avio_rb32(pb); /* uncompressed size */
    cmov_len = atom.size - 6 * 4;

    cmov_data = av_malloc(cmov_len);
    if (!cmov_data)
        return AVERROR(ENOMEM);
    moov_data = av_malloc(moov_len);
    if (!moov_data) {
        av_free(cmov_data);
        return AVERROR(ENOMEM);
    }
    ret = ffio_read_size(pb, cmov_data, cmov_len);
    if (ret < 0)
        goto free_and_return;

    ret = AVERROR_INVALIDDATA;
    if (uncompress (moov_data, (uLongf *) &moov_len, (const Bytef *)cmov_data, cmov_len) != Z_OK)
        goto free_and_return;
    ffio_init_context(&ctx, moov_data, moov_len, 0, NULL, NULL, NULL, NULL);
    ctx.pub.seekable = AVIO_SEEKABLE_NORMAL;
    atom.type = MKTAG('m','o','o','v');
    atom.size = moov_len;
    ret = mov_read_default(c, &ctx.pub, atom);
free_and_return:
    av_free(moov_data);
    av_free(cmov_data);
    return ret;
#else
    av_log(c->fc, AV_LOG_ERROR, "this file requires zlib support compiled in\n");
    return AVERROR(ENOSYS);
#endif
}

Project: FFmpeg
File: mov.c

static int mov_read_kind(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
    AVFormatContext *ctx = c->fc;
    AVStream *st = NULL;
    AVBPrint scheme_buf, value_buf;
    int64_t scheme_str_len = 0, value_str_len = 0;
    int version, flags, ret = AVERROR_BUG;
    int64_t size = atom.size;

    if (atom.size < 6)
        // 4 bytes for version + flags, 2x 1 byte for null
        return AVERROR_INVALIDDATA;

    if (c->fc->nb_streams < 1)
        return 0;
    st = c->fc->streams[c->fc->nb_streams-1];

    version = avio_r8(pb);
    flags   = avio_rb24(pb);
    size   -= 4;

    if (version != 0 || flags != 0) {
        av_log(ctx, AV_LOG_ERROR,
               "Unsupported 'kind' box with version %d, flags: %x",
               version, flags);
        return AVERROR_INVALIDDATA;
    }

    av_bprint_init(&scheme_buf, 0, AV_BPRINT_SIZE_UNLIMITED);
    av_bprint_init(&value_buf,  0, AV_BPRINT_SIZE_UNLIMITED);

    if ((scheme_str_len = ff_read_string_to_bprint_overwrite(pb, &scheme_buf,
                                                             size)) < 0) {
        ret = scheme_str_len;
        goto cleanup;
    }

    if (scheme_str_len + 1 >= size) {
        // we need to have another string, even if nullptr.
        // we check with + 1 since we expect that if size was not hit,
        // an additional null was read.
        ret = AVERROR_INVALIDDATA;
        goto cleanup;
    }

    size -= scheme_str_len + 1;

    if ((value_str_len = ff_read_string_to_bprint_overwrite(pb, &value_buf,
                                                            size)) < 0) {
        ret = value_str_len;
        goto cleanup;
    }

    if (value_str_len == size) {
        // in case of no trailing null, box is not valid.
        ret = AVERROR_INVALIDDATA;
        goto cleanup;
    }

    av_log(ctx, AV_LOG_TRACE,
           "%s stream %d KindBox(scheme: %s, value: %s)\n",
           av_get_media_type_string(st->codecpar->codec_type),
           st->index,
           scheme_buf.str, value_buf.str);

    for (int i = 0; ff_mov_track_kind_table[i].scheme_uri; i++) {
        const struct MP4TrackKindMapping map = ff_mov_track_kind_table[i];
        if (!av_strstart(scheme_buf.str, map.scheme_uri, NULL))
            continue;

        for (int j = 0; map.value_maps[j].disposition; j++) {
            const struct MP4TrackKindValueMapping value_map = map.value_maps[j];
            if (!av_strstart(value_buf.str, value_map.value, NULL))
                continue;

            st->disposition |= value_map.disposition;
        }
    }

    ret = 0;

cleanup:

    av_bprint_finalize(&scheme_buf, NULL);
    av_bprint_finalize(&value_buf,  NULL);

    return ret;
}

Project: FFmpeg
File: mov.c

static int mov_read_timecode_track(AVFormatContext *s, AVStream *st)
{
    MOVStreamContext *sc = st->priv_data;
    FFStream *const sti = ffstream(st);
    int flags = 0;
    int64_t cur_pos = avio_tell(sc->pb);
    int64_t value;
    AVRational tc_rate = st->avg_frame_rate;
    int tmcd_nb_frames = sc->tmcd_nb_frames;
    int rounded_tc_rate;

    if (!sti->nb_index_entries)
        return -1;

    if (!tc_rate.num || !tc_rate.den || !tmcd_nb_frames)
        return -1;

    avio_seek(sc->pb, sti->index_entries->pos, SEEK_SET);
    value = avio_rb32(s->pb);

    if (sc->tmcd_flags & 0x0001) flags |= AV_TIMECODE_FLAG_DROPFRAME;
    if (sc->tmcd_flags & 0x0002) flags |= AV_TIMECODE_FLAG_24HOURSMAX;
    if (sc->tmcd_flags & 0x0004) flags |= AV_TIMECODE_FLAG_ALLOWNEGATIVE;

    /* Assume Counter flag is set to 1 in tmcd track (even though it is likely
     * not the case) and thus assume "frame number format" instead of QT one.
     * No sample with tmcd track can be found with a QT timecode at the moment,
     * despite what the tmcd track "suggests" (Counter flag set to 0 means QT
     * format). */

    /* 60 fps content have tmcd_nb_frames set to 30 but tc_rate set to 60, so
     * we multiply the frame number with the quotient.
     * See tickets #9492, #9710. */
    rounded_tc_rate = (tc_rate.num + tc_rate.den / 2) / tc_rate.den;
    /* Work around files where tmcd_nb_frames is rounded down from frame rate
     * instead of up. See ticket #5978. */
    if (tmcd_nb_frames == tc_rate.num / tc_rate.den &&
        s->strict_std_compliance < FF_COMPLIANCE_STRICT)
        tmcd_nb_frames = rounded_tc_rate;
    value = av_rescale(value, rounded_tc_rate, tmcd_nb_frames);

    parse_timecode_in_framenum_format(s, st, value, flags);

    avio_seek(sc->pb, cur_pos, SEEK_SET);
    return 0;
}

Project: FFmpeg
File: mov.c

static int mov_finalize_stsd_codec(MOVContext *c, AVIOContext *pb,
                                   AVStream *st, MOVStreamContext *sc)
{
    FFStream *const sti = ffstream(st);

    if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
        !st->codecpar->sample_rate && sc->time_scale > 1)
        st->codecpar->sample_rate = sc->time_scale;

    /* special codec parameters handling */
    switch (st->codecpar->codec_id) {
#if CONFIG_DV_DEMUXER
    case AV_CODEC_ID_DVAUDIO:
        c->dv_fctx = avformat_alloc_context();
        if (!c->dv_fctx) {
            av_log(c->fc, AV_LOG_ERROR, "dv demux context alloc error\n");
            return AVERROR(ENOMEM);
        }
        c->dv_demux = avpriv_dv_init_demux(c->dv_fctx);
        if (!c->dv_demux) {
            av_log(c->fc, AV_LOG_ERROR, "dv demux context init error\n");
            return AVERROR(ENOMEM);
        }
        sc->dv_audio_container = 1;
        st->codecpar->codec_id    = AV_CODEC_ID_PCM_S16LE;
        break;
#endif
    /* no ifdef since parameters are always those */
    case AV_CODEC_ID_QCELP:
        av_channel_layout_uninit(&st->codecpar->ch_layout);
        st->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO;
        // force sample rate for qcelp when not stored in mov
        if (st->codecpar->codec_tag != MKTAG('Q','c','l','p'))
            st->codecpar->sample_rate = 8000;
        // FIXME: Why is the following needed for some files?
        sc->samples_per_frame = 160;
        if (!sc->bytes_per_frame)
            sc->bytes_per_frame = 35;
        break;
    case AV_CODEC_ID_AMR_NB:
        av_channel_layout_uninit(&st->codecpar->ch_layout);
        st->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO;
        /* force sample rate for amr, stsd in 3gp does not store sample rate */
        st->codecpar->sample_rate = 8000;
        break;
    case AV_CODEC_ID_AMR_WB:
        av_channel_layout_uninit(&st->codecpar->ch_layout);
        st->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO;
        st->codecpar->sample_rate = 16000;
        break;
    case AV_CODEC_ID_MP2:
    case AV_CODEC_ID_MP3:
        /* force type after stsd for m1a hdlr */
        st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
        break;
    case AV_CODEC_ID_GSM:
    case AV_CODEC_ID_ADPCM_MS:
    case AV_CODEC_ID_ADPCM_IMA_WAV:
    case AV_CODEC_ID_ILBC:
    case AV_CODEC_ID_MACE3:
    case AV_CODEC_ID_MACE6:
    case AV_CODEC_ID_QDM2:
        st->codecpar->block_align = sc->bytes_per_frame;
        break;
    case AV_CODEC_ID_ALAC:
        if (st->codecpar->extradata_size == 36) {
            int channel_count = AV_RB8(st->codecpar->extradata + 21);
            if (st->codecpar->ch_layout.nb_channels != channel_count) {
                av_channel_layout_uninit(&st->codecpar->ch_layout);
                st->codecpar->ch_layout.order = AV_CHANNEL_ORDER_UNSPEC;
                st->codecpar->ch_layout.nb_channels = channel_count;
            }
            st->codecpar->sample_rate = AV_RB32(st->codecpar->extradata + 32);
        }
        break;
    case AV_CODEC_ID_AC3:
    case AV_CODEC_ID_EAC3:
    case AV_CODEC_ID_MPEG1VIDEO:
    case AV_CODEC_ID_VC1:
    case AV_CODEC_ID_VP8:
    case AV_CODEC_ID_VP9:
        sti->need_parsing = AVSTREAM_PARSE_FULL;
        break;
    case AV_CODEC_ID_AV1:
        /* field_order detection of H264 requires parsing */
    case AV_CODEC_ID_H264:
        sti->need_parsing = AVSTREAM_PARSE_HEADERS;
        break;
    default:
        break;
    }
    return 0;
}

Project: FFmpeg
File: mov.c

static int mov_parse_stsd_data(MOVContext *c, AVIOContext *pb,
                                AVStream *st, MOVStreamContext *sc,
                                int64_t size)
{
    int ret;

    if (st->codecpar->codec_tag == MKTAG('t','m','c','d')) {
        if ((int)size != size)
            return AVERROR(ENOMEM);

        ret = ff_get_extradata(c->fc, st->codecpar, pb, size);
        if (ret < 0)
            return ret;
        if (size > 16) {
            MOVStreamContext *tmcd_ctx = st->priv_data;
            int val;
            val = AV_RB32(st->codecpar->extradata + 4);
            tmcd_ctx->tmcd_flags = val;
            st->avg_frame_rate.num = AV_RB32(st->codecpar->extradata + 8); /* timescale */
            st->avg_frame_rate.den = AV_RB32(st->codecpar->extradata + 12); /* frameDuration */
            tmcd_ctx->tmcd_nb_frames = st->codecpar->extradata[16]; /* number of frames */
            if (size > 30) {
                uint32_t len = AV_RB32(st->codecpar->extradata + 18); /* name atom length */
                uint32_t format = AV_RB32(st->codecpar->extradata + 22);
                if (format == AV_RB32("name") && (int64_t)size >= (int64_t)len + 18) {
                    uint16_t str_size = AV_RB16(st->codecpar->extradata + 26); /* string length */
                    if (str_size > 0 && size >= (int)str_size + 30 &&
                        st->codecpar->extradata[30] /* Don't add empty string */) {
                        char *reel_name = av_malloc(str_size + 1);
                        if (!reel_name)
                            return AVERROR(ENOMEM);
                        memcpy(reel_name, st->codecpar->extradata + 30, str_size);
                        reel_name[str_size] = 0; /* Add null terminator */
                        av_dict_set(&st->metadata, "reel_name", reel_name,
                                    AV_DICT_DONT_STRDUP_VAL);
                    }
                }
            }
        }
    } else {
        /* other codec type, just skip (rtp, mp4s ...) */
        avio_skip(pb, size);
    }
    return 0;
}

Project: FFmpeg
File: mov.c

static int mov_read_mdhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
    AVStream *st;
    MOVStreamContext *sc;
    int version;
    char language[4] = {0};
    unsigned lang;
    int64_t creation_time;

    if (c->fc->nb_streams < 1)
        return 0;
    st = c->fc->streams[c->fc->nb_streams-1];
    sc = st->priv_data;

    if (sc->time_scale) {
        av_log(c->fc, AV_LOG_ERROR, "Multiple mdhd?\n");
        return AVERROR_INVALIDDATA;
    }

    version = avio_r8(pb);
    if (version > 1) {
        avpriv_request_sample(c->fc, "Version %d", version);
        return AVERROR_PATCHWELCOME;
    }
    avio_rb24(pb); /* flags */
    if (version == 1) {
        creation_time = avio_rb64(pb);
        avio_rb64(pb);
    } else {
        creation_time = avio_rb32(pb);
        avio_rb32(pb); /* modification time */
    }
    mov_metadata_creation_time(&st->metadata, creation_time, c->fc);

    sc->time_scale = avio_rb32(pb);
    if (sc->time_scale <= 0) {
        av_log(c->fc, AV_LOG_ERROR, "Invalid mdhd time scale %d, defaulting to 1\n", sc->time_scale);
        sc->time_scale = 1;
    }
    st->duration = (version == 1) ? avio_rb64(pb) : avio_rb32(pb); /* duration */

    lang = avio_rb16(pb); /* language */
    if (ff_mov_lang_to_iso639(lang, language))
        av_dict_set(&st->metadata, "language", language, 0);
    avio_rb16(pb); /* quality */

    return 0;
}

Project: FFmpeg
File: mov.c

static int mov_read_ddts(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
#define DDTS_SIZE 20
    uint8_t buf[DDTS_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
    AVStream *st = NULL;
    uint32_t frame_duration_code = 0;
    uint32_t channel_layout_code = 0;
    GetBitContext gb;
    int ret;

    if ((ret = ffio_read_size(pb, buf, DDTS_SIZE)) < 0)
        return ret;

    init_get_bits(&gb, buf, 8 * DDTS_SIZE);

    if (c->fc->nb_streams < 1) {
        return 0;
    }
    st = c->fc->streams[c->fc->nb_streams-1];

    st->codecpar->sample_rate = get_bits_long(&gb, 32);
    if (st->codecpar->sample_rate <= 0) {
        av_log(c->fc, AV_LOG_ERROR, "Invalid sample rate %d\n", st->codecpar->sample_rate);
        return AVERROR_INVALIDDATA;
    }
    skip_bits_long(&gb, 32); /* max bitrate */
    st->codecpar->bit_rate = get_bits_long(&gb, 32);
    st->codecpar->bits_per_coded_sample = get_bits(&gb, 8);
    frame_duration_code = get_bits(&gb, 2);
    skip_bits(&gb, 30); /* various fields */
    channel_layout_code = get_bits(&gb, 16);

    st->codecpar->frame_size =
            (frame_duration_code == 0) ? 512 :
            (frame_duration_code == 1) ? 1024 :
            (frame_duration_code == 2) ? 2048 :
            (frame_duration_code == 3) ? 4096 : 0;

    if (channel_layout_code > 0xff) {
        av_log(c->fc, AV_LOG_WARNING, "Unsupported DTS audio channel layout\n");
    }
    av_channel_layout_uninit(&st->codecpar->ch_layout);
    av_channel_layout_from_mask(&st->codecpar->ch_layout,
            ((channel_layout_code & 0x1) ? AV_CH_FRONT_CENTER : 0) |
            ((channel_layout_code & 0x2) ? AV_CH_FRONT_LEFT : 0) |
            ((channel_layout_code & 0x2) ? AV_CH_FRONT_RIGHT : 0) |
            ((channel_layout_code & 0x4) ? AV_CH_SIDE_LEFT : 0) |
            ((channel_layout_code & 0x4) ? AV_CH_SIDE_RIGHT : 0) |
            ((channel_layout_code & 0x8) ? AV_CH_LOW_FREQUENCY : 0));

    return 0;
}

Project: FFmpeg
File: mov.c

static int mov_read_svq3(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
    return mov_read_extradata(c, pb, atom, AV_CODEC_ID_SVQ3);
}

Project: FFmpeg
File: mov.c

static int mov_codec_id(AVStream *st, uint32_t format)
{
    int id = ff_codec_get_id(ff_codec_movaudio_tags, format);

    if (id <= 0 &&
        ((format & 0xFFFF) == 'm' + ('s' << 8) ||
         (format & 0xFFFF) == 'T' + ('S' << 8)))
        id = ff_codec_get_id(ff_codec_wav_tags, av_bswap32(format) & 0xFFFF);

    if (st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO && id > 0) {
        st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
    } else if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO &&
               /* skip old ASF MPEG-4 tag */
               format && format != MKTAG('m','p','4','s')) {
        id = ff_codec_get_id(ff_codec_movvideo_tags, format);
        if (id <= 0)
            id = ff_codec_get_id(ff_codec_bmp_tags, format);
        if (id > 0)
            st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
        else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA ||
                    (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE &&
                    st->codecpar->codec_id == AV_CODEC_ID_NONE)) {
            id = ff_codec_get_id(ff_codec_movsubtitle_tags, format);
            if (id > 0)
                st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE;
            else
                id = ff_codec_get_id(ff_codec_movdata_tags, format);
        }
    }

    st->codecpar->codec_tag = format;

    return id;
}

Project: FFmpeg
File: mov.c

static int mov_read_fiel(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
    AVStream *st;
    unsigned mov_field_order;
    enum AVFieldOrder decoded_field_order = AV_FIELD_UNKNOWN;

    if (c->fc->nb_streams < 1) // will happen with jp2 files
        return 0;
    st = c->fc->streams[c->fc->nb_streams-1];
    if (atom.size < 2)
        return AVERROR_INVALIDDATA;
    mov_field_order = avio_rb16(pb);
    if ((mov_field_order & 0xFF00) == 0x0100)
        decoded_field_order = AV_FIELD_PROGRESSIVE;
    else if ((mov_field_order & 0xFF00) == 0x0200) {
        switch (mov_field_order & 0xFF) {
        case 0x01: decoded_field_order = AV_FIELD_TT;
                   break;
        case 0x06: decoded_field_order = AV_FIELD_BB;
                   break;
        case 0x09: decoded_field_order = AV_FIELD_TB;
                   break;
        case 0x0E: decoded_field_order = AV_FIELD_BT;
                   break;
        }
    }
    if (decoded_field_order == AV_FIELD_UNKNOWN && mov_field_order) {
        av_log(c->fc, AV_LOG_ERROR, "Unknown MOV field order 0x%04x\n", mov_field_order);
    }
    st->codecpar->field_order = decoded_field_order;

    return 0;
}

Project: FFmpeg
File: mov.c

static int cbcs_scheme_decrypt(MOVContext *c, MOVStreamContext *sc, AVEncryptionInfo *sample, uint8_t *input, int size)
{
    int i, ret, rem_bytes;
    uint8_t iv[16];
    uint8_t *data;

    if (!sc->cenc.aes_ctx) {
        /* initialize the cipher */
        sc->cenc.aes_ctx = av_aes_alloc();
        if (!sc->cenc.aes_ctx) {
            return AVERROR(ENOMEM);
        }

        ret = av_aes_init(sc->cenc.aes_ctx, c->decryption_key, 16 * 8, 1);
        if (ret < 0) {
            return ret;
        }
    }

    /* whole-block full sample encryption */
    if (!sample->subsample_count) {
        /* decrypt the whole packet */
        memcpy(iv, sample->iv, 16);
        av_aes_crypt(sc->cenc.aes_ctx, input, input, size/16, iv, 1);
        return 0;
    } else if (!sample->crypt_byte_block && !sample->skip_byte_block) {
        av_log(c->fc, AV_LOG_ERROR, "pattern encryption is not present in 'cbcs' scheme\n");
        return AVERROR_INVALIDDATA;
    }

    for (i = 0; i < sample->subsample_count; i++) {
        if (sample->subsamples[i].bytes_of_clear_data + sample->subsamples[i].bytes_of_protected_data > size) {
            av_log(c->fc, AV_LOG_ERROR, "subsample size exceeds the packet size left\n");
            return AVERROR_INVALIDDATA;
        }

        /* skip the clear bytes */
        input += sample->subsamples[i].bytes_of_clear_data;
        size -= sample->subsamples[i].bytes_of_clear_data;

        /* decrypt the encrypted bytes */
        memcpy(iv, sample->iv, 16);
        data = input;
        rem_bytes = sample->subsamples[i].bytes_of_protected_data;
        while (rem_bytes > 0) {
            if (rem_bytes < 16*sample->crypt_byte_block) {
                break;
            }
            av_aes_crypt(sc->cenc.aes_ctx, data, data, sample->crypt_byte_block, iv, 1);
            data += 16*sample->crypt_byte_block;
            rem_bytes -= 16*sample->crypt_byte_block;
            data += FFMIN(16*sample->skip_byte_block, rem_bytes);
            rem_bytes -= FFMIN(16*sample->skip_byte_block, rem_bytes);
        }
        input += sample->subsamples[i].bytes_of_protected_data;
        size -= sample->subsamples[i].bytes_of_protected_data;
    }

    if (size > 0) {
        av_log(c->fc, AV_LOG_ERROR, "leftover packet bytes after subsample processing\n");
        return AVERROR_INVALIDDATA;
    }

    return 0;
}

Project: FFmpeg
File: mov.c

static int mov_read_seek(AVFormatContext *s, int stream_index, int64_t sample_time, int flags)
{
    MOVContext *mc = s->priv_data;
    AVStream *st;
    FFStream *sti;
    int sample;
    int i;

    if (stream_index >= s->nb_streams)
        return AVERROR_INVALIDDATA;

    st = s->streams[stream_index];
    sti = ffstream(st);
    sample = mov_seek_stream(s, st, sample_time, flags);
    if (sample < 0)
        return sample;

    if (mc->seek_individually) {
        /* adjust seek timestamp to found sample timestamp */
        int64_t seek_timestamp = sti->index_entries[sample].timestamp;
        sti->skip_samples = mov_get_skip_samples(st, sample);

        for (i = 0; i < s->nb_streams; i++) {
            AVStream *const st  = s->streams[i];
            FFStream *const sti = ffstream(st);
            int64_t timestamp;

            if (stream_index == i)
                continue;

            timestamp = av_rescale_q(seek_timestamp, s->streams[stream_index]->time_base, st->time_base);
            sample = mov_seek_stream(s, st, timestamp, flags);
            if (sample >= 0)
                sti->skip_samples = mov_get_skip_samples(st, sample);
        }
    } else {
        for (i = 0; i < s->nb_streams; i++) {
            MOVStreamContext *sc;
            st = s->streams[i];
            sc = st->priv_data;
            mov_current_sample_set(sc, 0);
        }
        while (1) {
            MOVStreamContext *sc;
            AVIndexEntry *entry = mov_find_next_sample(s, &st);
            if (!entry)
                return AVERROR_INVALIDDATA;
            sc = st->priv_data;
            if (sc->ffindex == stream_index && sc->current_sample == sample)
                break;
            mov_current_sample_inc(sc);
        }
    }
    return 0;
}

Project: FFmpeg
File: mov.c

static int mov_metadata_hmmt(MOVContext *c, AVIOContext *pb, unsigned len)
{
    int i, n_hmmt;

    if (len < 2)
        return 0;
    if (c->ignore_chapters)
        return 0;

    n_hmmt = avio_rb32(pb);
    if (n_hmmt > len / 4)
        return AVERROR_INVALIDDATA;
    for (i = 0; i < n_hmmt && !pb->eof_reached; i++) {
        int moment_time = avio_rb32(pb);
        avpriv_new_chapter(c->fc, i, av_make_q(1, 1000), moment_time, AV_NOPTS_VALUE, NULL);
    }
    if (avio_feof(pb))
        return AVERROR_INVALIDDATA;
    return 0;
}

Project: FFmpeg
File: mov.c

static void mov_parse_stsd_video(MOVContext *c, AVIOContext *pb,
                                 AVStream *st, MOVStreamContext *sc)
{
    uint8_t codec_name[32] = { 0 };
    int64_t stsd_start;
    unsigned int len;
    uint32_t id = 0;

    /* The first 16 bytes of the video sample description are already
     * read in ff_mov_read_stsd_entries() */
    stsd_start = avio_tell(pb) - 16;

    avio_rb16(pb); /* version */
    avio_rb16(pb); /* revision level */
    id = avio_rl32(pb); /* vendor */
    av_dict_set(&st->metadata, "vendor_id", av_fourcc2str(id), 0);
    avio_rb32(pb); /* temporal quality */
    avio_rb32(pb); /* spatial quality */

    st->codecpar->width  = avio_rb16(pb); /* width */
    st->codecpar->height = avio_rb16(pb); /* height */

    avio_rb32(pb); /* horiz resolution */
    avio_rb32(pb); /* vert resolution */
    avio_rb32(pb); /* data size, always 0 */
    avio_rb16(pb); /* frames per samples */

    len = avio_r8(pb); /* codec name, pascal string */
    if (len > 31)
        len = 31;
    mov_read_mac_string(c, pb, len, codec_name, sizeof(codec_name));
    if (len < 31)
        avio_skip(pb, 31 - len);

    if (codec_name[0])
        av_dict_set(&st->metadata, "encoder", codec_name, 0);

    /* codec_tag YV12 triggers an UV swap in rawdec.c */
    if (!strncmp(codec_name, "Planar Y'CbCr 8-bit 4:2:0", 25)) {
        st->codecpar->codec_tag = MKTAG('I', '4', '2', '0');
        st->codecpar->width &= ~1;
        st->codecpar->height &= ~1;
    }
    /* Flash Media Server uses tag H.263 with Sorenson Spark */
    if (st->codecpar->codec_tag == MKTAG('H','2','6','3') &&
        !strncmp(codec_name, "Sorenson H263", 13))
        st->codecpar->codec_id = AV_CODEC_ID_FLV1;

    st->codecpar->bits_per_coded_sample = avio_rb16(pb); /* depth */

    avio_seek(pb, stsd_start, SEEK_SET);

    if (ff_get_qtpalette(st->codecpar->codec_id, pb, sc->palette)) {
        st->codecpar->bits_per_coded_sample &= 0x1F;
        sc->has_palette = 1;
    }
}

Project: FFmpeg
File: mov.c

static int mov_read_dref(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
    AVStream *st;
    MOVStreamContext *sc;
    int entries, i, j;

    if (c->fc->nb_streams < 1)
        return 0;
    st = c->fc->streams[c->fc->nb_streams-1];
    sc = st->priv_data;

    avio_rb32(pb); // version + flags
    entries = avio_rb32(pb);
    if (!entries ||
        entries >  (atom.size - 1) / MIN_DATA_ENTRY_BOX_SIZE + 1 ||
        entries >= UINT_MAX / sizeof(*sc->drefs))
        return AVERROR_INVALIDDATA;

    for (i = 0; i < sc->drefs_count; i++) {
        MOVDref *dref = &sc->drefs[i];
        av_freep(&dref->path);
        av_freep(&dref->dir);
    }
    av_free(sc->drefs);
    sc->drefs_count = 0;
    sc->drefs = av_mallocz(entries * sizeof(*sc->drefs));
    if (!sc->drefs)
        return AVERROR(ENOMEM);
    sc->drefs_count = entries;

    for (i = 0; i < entries; i++) {
        MOVDref *dref = &sc->drefs[i];
        uint32_t size = avio_rb32(pb);
        int64_t next = avio_tell(pb);

        if (size < 12 || next < 0 || next > INT64_MAX - size)
            return AVERROR_INVALIDDATA;

        next += size - 4;

        dref->type = avio_rl32(pb);
        avio_rb32(pb); // version + flags

        if (dref->type == MKTAG('a','l','i','s') && size > 150) {
            /* macintosh alias record */
            uint16_t volume_len, len;
            int16_t type;
            int ret;

            avio_skip(pb, 10);

            volume_len = avio_r8(pb);
            volume_len = FFMIN(volume_len, 27);
            ret = ffio_read_size(pb, dref->volume, 27);
            if (ret < 0)
                return ret;
            dref->volume[volume_len] = 0;
            av_log(c->fc, AV_LOG_DEBUG, "volume %s, len %d\n", dref->volume, volume_len);

            avio_skip(pb, 12);

            len = avio_r8(pb);
            len = FFMIN(len, 63);
            ret = ffio_read_size(pb, dref->filename, 63);
            if (ret < 0)
                return ret;
            dref->filename[len] = 0;
            av_log(c->fc, AV_LOG_DEBUG, "filename %s, len %d\n", dref->filename, len);

            avio_skip(pb, 16);

            /* read next level up_from_alias/down_to_target */
            dref->nlvl_from = avio_rb16(pb);
            dref->nlvl_to   = avio_rb16(pb);
            av_log(c->fc, AV_LOG_DEBUG, "nlvl from %d, nlvl to %d\n",
                   dref->nlvl_from, dref->nlvl_to);

            avio_skip(pb, 16);

            for (type = 0; type != -1 && avio_tell(pb) < next; ) {
                if (avio_feof(pb))
                    return AVERROR_EOF;
                type = avio_rb16(pb);
                len = avio_rb16(pb);
                av_log(c->fc, AV_LOG_DEBUG, "type %d, len %d\n", type, len);
                if (len&1)
                    len += 1;
                if (type == 2) { // absolute path
                    av_free(dref->path);
                    dref->path = av_mallocz(len+1);
                    if (!dref->path)
                        return AVERROR(ENOMEM);

                    ret = ffio_read_size(pb, dref->path, len);
                    if (ret < 0) {
                        av_freep(&dref->path);
                        return ret;
                    }
                    if (len > volume_len && !strncmp(dref->path, dref->volume, volume_len)) {
                        len -= volume_len;
                        memmove(dref->path, dref->path+volume_len, len);
                        dref->path[len] = 0;
                    }
                    // trim string of any ending zeros
                    for (j = len - 1; j >= 0; j--) {
                        if (dref->path[j] == 0)
                            len--;
                        else
                            break;
                    }
                    for (j = 0; j < len; j++)
                        if (dref->path[j] == ':' || dref->path[j] == 0)
                            dref->path[j] = '/';
                    av_log(c->fc, AV_LOG_DEBUG, "path %s\n", dref->path);
                } else if (type == 0) { // directory name
                    av_free(dref->dir);
                    dref->dir = av_malloc(len+1);
                    if (!dref->dir)
                        return AVERROR(ENOMEM);

                    ret = ffio_read_size(pb, dref->dir, len);
                    if (ret < 0) {
                        av_freep(&dref->dir);
                        return ret;
                    }
                    dref->dir[len] = 0;
                    for (j = 0; j < len; j++)
                        if (dref->dir[j] == ':')
                            dref->dir[j] = '/';
                    av_log(c->fc, AV_LOG_DEBUG, "dir %s\n", dref->dir);
                } else
                    avio_skip(pb, len);
            }
        } else {
            av_log(c->fc, AV_LOG_DEBUG, "Unknown dref type 0x%08"PRIx32" size %"PRIu32"\n",
                   dref->type, size);
            entries--;
            i--;
        }
        avio_seek(pb, next, SEEK_SET);
    }
    return 0;
}

Project: FFmpeg
File: mov.c

static int find_prev_closest_index(AVStream *st,
                                   AVIndexEntry *e_old,
                                   int nb_old,
                                   MOVCtts* ctts_data,
                                   int64_t ctts_count,
                                   int64_t timestamp_pts,
                                   int flag,
                                   int64_t* index,
                                   int64_t* ctts_index,
                                   int64_t* ctts_sample)
{
    MOVStreamContext *msc = st->priv_data;
    FFStream *const sti = ffstream(st);
    AVIndexEntry *e_keep = sti->index_entries;
    int nb_keep = sti->nb_index_entries;
    int64_t i = 0;
    int64_t index_ctts_count;

    av_assert0(index);

    // If dts_shift > 0, then all the index timestamps will have to be offset by
    // at least dts_shift amount to obtain PTS.
    // Hence we decrement the searched timestamp_pts by dts_shift to find the closest index element.
    if (msc->dts_shift > 0) {
        timestamp_pts -= msc->dts_shift;
    }

    sti->index_entries    = e_old;
    sti->nb_index_entries = nb_old;
    *index = av_index_search_timestamp(st, timestamp_pts, flag | AVSEEK_FLAG_BACKWARD);

    // Keep going backwards in the index entries until the timestamp is the same.
    if (*index >= 0) {
        for (i = *index; i > 0 && e_old[i].timestamp == e_old[i - 1].timestamp;
             i--) {
            if ((flag & AVSEEK_FLAG_ANY) ||
                (e_old[i - 1].flags & AVINDEX_KEYFRAME)) {
                *index = i - 1;
            }
        }
    }

    // If we have CTTS then refine the search, by searching backwards over PTS
    // computed by adding corresponding CTTS durations to index timestamps.
    if (ctts_data && *index >= 0) {
        av_assert0(ctts_index);
        av_assert0(ctts_sample);
        // Find out the ctts_index for the found frame.
        *ctts_index = 0;
        *ctts_sample = 0;
        for (index_ctts_count = 0; index_ctts_count < *index; index_ctts_count++) {
            if (*ctts_index < ctts_count) {
                (*ctts_sample)++;
                if (ctts_data[*ctts_index].count == *ctts_sample) {
                    (*ctts_index)++;
                    *ctts_sample = 0;
                }
            }
        }

        while (*index >= 0 && (*ctts_index) >= 0 && (*ctts_index) < ctts_count) {
            // Find a "key frame" with PTS <= timestamp_pts (So that we can decode B-frames correctly).
            // No need to add dts_shift to the timestamp here becase timestamp_pts has already been
            // compensated by dts_shift above.
            if ((e_old[*index].timestamp + ctts_data[*ctts_index].duration) <= timestamp_pts &&
                (e_old[*index].flags & AVINDEX_KEYFRAME)) {
                break;
            }

            (*index)--;
            if (*ctts_sample == 0) {
                (*ctts_index)--;
                if (*ctts_index >= 0)
                  *ctts_sample = ctts_data[*ctts_index].count - 1;
            } else {
                (*ctts_sample)--;
            }
        }
    }

    /* restore AVStream state*/
    sti->index_entries    = e_keep;
    sti->nb_index_entries = nb_keep;
    return *index >= 0 ? 0 : -1;
}

Project: FFmpeg
File: mov.c

static int mov_parse_uuid_spherical(MOVStreamContext *sc, AVIOContext *pb, size_t len)
{
    int ret = 0;
    uint8_t *buffer = av_malloc(len + 1);
    const char *val;

    if (!buffer)
        return AVERROR(ENOMEM);
    buffer[len] = '\0';

    ret = ffio_read_size(pb, buffer, len);
    if (ret < 0)
        goto out;

    /* Check for mandatory keys and values, try to support XML as best-effort */
    if (!sc->spherical &&
        av_stristr(buffer, "<GSpherical:StitchingSoftware>") &&
        (val = av_stristr(buffer, "<GSpherical:Spherical>")) &&
        av_stristr(val, "true") &&
        (val = av_stristr(buffer, "<GSpherical:Stitched>")) &&
        av_stristr(val, "true") &&
        (val = av_stristr(buffer, "<GSpherical:ProjectionType>")) &&
        av_stristr(val, "equirectangular")) {
        sc->spherical = av_spherical_alloc(&sc->spherical_size);
        if (!sc->spherical)
            goto out;

        sc->spherical->projection = AV_SPHERICAL_EQUIRECTANGULAR;

        if (av_stristr(buffer, "<GSpherical:StereoMode>") && !sc->stereo3d) {
            enum AVStereo3DType mode;

            if (av_stristr(buffer, "left-right"))
                mode = AV_STEREO3D_SIDEBYSIDE;
            else if (av_stristr(buffer, "top-bottom"))
                mode = AV_STEREO3D_TOPBOTTOM;
            else
                mode = AV_STEREO3D_2D;

            sc->stereo3d = av_stereo3d_alloc();
            if (!sc->stereo3d)
                goto out;

            sc->stereo3d->type = mode;
        }

        /* orientation */
        val = av_stristr(buffer, "<GSpherical:InitialViewHeadingDegrees>");
        if (val)
            sc->spherical->yaw = strtol(val, NULL, 10) * (1 << 16);
        val = av_stristr(buffer, "<GSpherical:InitialViewPitchDegrees>");
        if (val)
            sc->spherical->pitch = strtol(val, NULL, 10) * (1 << 16);
        val = av_stristr(buffer, "<GSpherical:InitialViewRollDegrees>");
        if (val)
            sc->spherical->roll = strtol(val, NULL, 10) * (1 << 16);
    }

out:
    av_free(buffer);
    return ret;
}

Project: FFmpeg
File: mov.c

static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
    MOVFragment *frag = &c->fragment;
    AVStream *st = NULL;
    FFStream *sti = NULL;
    MOVStreamContext *sc;
    MOVCtts *ctts_data;
    uint64_t offset;
    int64_t dts, pts = AV_NOPTS_VALUE;
    int data_offset = 0;
    unsigned entries, first_sample_flags = frag->flags;
    int flags, distance, i;
    int64_t prev_dts = AV_NOPTS_VALUE;
    int next_frag_index = -1, index_entry_pos;
    size_t requested_size;
    size_t old_ctts_allocated_size;
    AVIndexEntry *new_entries;
    MOVFragmentStreamInfo * frag_stream_info;

    if (!frag->found_tfhd) {
        av_log(c->fc, AV_LOG_ERROR, "trun track id unknown, no tfhd was found\n");
        return AVERROR_INVALIDDATA;
    }

    for (i = 0; i < c->fc->nb_streams; i++) {
        if (c->fc->streams[i]->id == frag->track_id) {
            st = c->fc->streams[i];
            sti = ffstream(st);
            break;
        }
    }
    if (!st) {
        av_log(c->fc, AV_LOG_WARNING, "could not find corresponding track id %u\n", frag->track_id);
        return 0;
    }
    sc = st->priv_data;
    if (sc->pseudo_stream_id+1 != frag->stsd_id && sc->pseudo_stream_id != -1)
        return 0;

    // Find the next frag_index index that has a valid index_entry for
    // the current track_id.
    //
    // A valid index_entry means the trun for the fragment was read
    // and it's samples are in index_entries at the given position.
    // New index entries will be inserted before the index_entry found.
    index_entry_pos = sti->nb_index_entries;
    for (i = c->frag_index.current + 1; i < c->frag_index.nb_items; i++) {
        frag_stream_info = get_frag_stream_info(&c->frag_index, i, frag->track_id);
        if (frag_stream_info && frag_stream_info->index_entry >= 0) {
            next_frag_index = i;
            index_entry_pos = frag_stream_info->index_entry;
            break;
        }
    }
    av_assert0(index_entry_pos <= sti->nb_index_entries);

    avio_r8(pb); /* version */
    flags = avio_rb24(pb);
    entries = avio_rb32(pb);
    av_log(c->fc, AV_LOG_TRACE, "flags 0x%x entries %u\n", flags, entries);

    if ((uint64_t)entries+sc->ctts_count >= UINT_MAX/sizeof(*sc->ctts_data))
        return AVERROR_INVALIDDATA;
    if (flags & MOV_TRUN_DATA_OFFSET)        data_offset        = avio_rb32(pb);
    if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS) first_sample_flags = avio_rb32(pb);

    frag_stream_info = get_current_frag_stream_info(&c->frag_index);
    if (frag_stream_info) {
        if (frag_stream_info->next_trun_dts != AV_NOPTS_VALUE) {
            dts = frag_stream_info->next_trun_dts - sc->time_offset;
        } else if (frag_stream_info->first_tfra_pts != AV_NOPTS_VALUE &&
            c->use_mfra_for == FF_MOV_FLAG_MFRA_PTS) {
            pts = frag_stream_info->first_tfra_pts;
            av_log(c->fc, AV_LOG_DEBUG, "found mfra time %"PRId64
                    ", using it for pts\n", pts);
        } else if (frag_stream_info->first_tfra_pts != AV_NOPTS_VALUE &&
            c->use_mfra_for == FF_MOV_FLAG_MFRA_DTS) {
            dts = frag_stream_info->first_tfra_pts;
            av_log(c->fc, AV_LOG_DEBUG, "found mfra time %"PRId64
                    ", using it for dts\n", pts);
        } else {
            int has_tfdt = frag_stream_info->tfdt_dts != AV_NOPTS_VALUE;
            int has_sidx = frag_stream_info->sidx_pts != AV_NOPTS_VALUE;
            int fallback_tfdt = !c->use_tfdt && !has_sidx && has_tfdt;
            int fallback_sidx =  c->use_tfdt && !has_tfdt && has_sidx;

            if (fallback_sidx) {
                av_log(c->fc, AV_LOG_DEBUG, "use_tfdt set but no tfdt found, using sidx instead\n");
            }
            if (fallback_tfdt) {
                av_log(c->fc, AV_LOG_DEBUG, "use_tfdt not set but no sidx found, using tfdt instead\n");
            }

            if (has_tfdt && c->use_tfdt || fallback_tfdt) {
                dts = frag_stream_info->tfdt_dts - sc->time_offset;
                av_log(c->fc, AV_LOG_DEBUG, "found tfdt time %"PRId64
                        ", using it for dts\n", dts);
            } else if (has_sidx && !c->use_tfdt || fallback_sidx) {
                // FIXME: sidx earliest_presentation_time is *PTS*, s.b.
                // pts = frag_stream_info->sidx_pts;
                dts = frag_stream_info->sidx_pts - sc->time_offset;
                av_log(c->fc, AV_LOG_DEBUG, "found sidx time %"PRId64
                        ", using it for dts\n", frag_stream_info->sidx_pts);
            } else {
                dts = sc->track_end - sc->time_offset;
                av_log(c->fc, AV_LOG_DEBUG, "found track end time %"PRId64
                        ", using it for dts\n", dts);
            }
        }
    } else {
        dts = sc->track_end - sc->time_offset;
        av_log(c->fc, AV_LOG_DEBUG, "found track end time %"PRId64
                ", using it for dts\n", dts);
    }
    offset   = frag->base_data_offset + data_offset;
    distance = 0;
    av_log(c->fc, AV_LOG_TRACE, "first sample flags 0x%x\n", first_sample_flags);

    // realloc space for new index entries
    if ((uint64_t)sti->nb_index_entries + entries >= UINT_MAX / sizeof(AVIndexEntry)) {
        entries = UINT_MAX / sizeof(AVIndexEntry) - sti->nb_index_entries;
        av_log(c->fc, AV_LOG_ERROR, "Failed to add index entry\n");
    }
    if (entries == 0)
        return 0;

    requested_size = (sti->nb_index_entries + entries) * sizeof(AVIndexEntry);
    new_entries = av_fast_realloc(sti->index_entries,
                                  &sti->index_entries_allocated_size,
                                  requested_size);
    if (!new_entries)
        return AVERROR(ENOMEM);
    sti->index_entries= new_entries;

    requested_size = (sti->nb_index_entries + entries) * sizeof(*sc->ctts_data);
    old_ctts_allocated_size = sc->ctts_allocated_size;
    ctts_data = av_fast_realloc(sc->ctts_data, &sc->ctts_allocated_size,
                                requested_size);
    if (!ctts_data)
        return AVERROR(ENOMEM);
    sc->ctts_data = ctts_data;

    // In case there were samples without ctts entries, ensure they get
    // zero valued entries. This ensures clips which mix boxes with and
    // without ctts entries don't pickup uninitialized data.
    memset((uint8_t*)(sc->ctts_data) + old_ctts_allocated_size, 0,
           sc->ctts_allocated_size - old_ctts_allocated_size);

    if (index_entry_pos < sti->nb_index_entries) {
        // Make hole in index_entries and ctts_data for new samples
        memmove(sti->index_entries + index_entry_pos + entries,
                sti->index_entries + index_entry_pos,
                sizeof(*sti->index_entries) *
                (sti->nb_index_entries - index_entry_pos));
        memmove(sc->ctts_data + index_entry_pos + entries,
                sc->ctts_data + index_entry_pos,
                sizeof(*sc->ctts_data) * (sc->ctts_count - index_entry_pos));
        if (index_entry_pos < sc->current_sample) {
            sc->current_sample += entries;
        }
    }

    sti->nb_index_entries += entries;
    sc->ctts_count = sti->nb_index_entries;

    // Record the index_entry position in frag_index of this fragment
    if (frag_stream_info) {
        frag_stream_info->index_entry = index_entry_pos;
        if (frag_stream_info->index_base < 0)
            frag_stream_info->index_base = index_entry_pos;
    }

    if (index_entry_pos > 0)
        prev_dts = sti->index_entries[index_entry_pos-1].timestamp;

    for (i = 0; i < entries && !pb->eof_reached; i++) {
        unsigned sample_size = frag->size;
        int sample_flags = i ? frag->flags : first_sample_flags;
        unsigned sample_duration = frag->duration;
        unsigned ctts_duration = 0;
        int keyframe = 0;
        int index_entry_flags = 0;

        if (flags & MOV_TRUN_SAMPLE_DURATION) sample_duration = avio_rb32(pb);
        if (flags & MOV_TRUN_SAMPLE_SIZE)     sample_size     = avio_rb32(pb);
        if (flags & MOV_TRUN_SAMPLE_FLAGS)    sample_flags    = avio_rb32(pb);
        if (flags & MOV_TRUN_SAMPLE_CTS)      ctts_duration   = avio_rb32(pb);

        mov_update_dts_shift(sc, ctts_duration, c->fc);
        if (pts != AV_NOPTS_VALUE) {
            dts = pts - sc->dts_shift;
            if (flags & MOV_TRUN_SAMPLE_CTS) {
                dts -= ctts_duration;
            } else {
                dts -= sc->time_offset;
            }
            av_log(c->fc, AV_LOG_DEBUG,
                   "pts %"PRId64" calculated dts %"PRId64
                   " sc->dts_shift %d ctts.duration %d"
                   " sc->time_offset %"PRId64
                   " flags & MOV_TRUN_SAMPLE_CTS %d\n",
                   pts, dts,
                   sc->dts_shift, ctts_duration,
                   sc->time_offset, flags & MOV_TRUN_SAMPLE_CTS);
            pts = AV_NOPTS_VALUE;
        }

        if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
            keyframe = 1;
        else
            keyframe =
                !(sample_flags & (MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC |
                                  MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES));
        if (keyframe) {
            distance = 0;
            index_entry_flags |= AVINDEX_KEYFRAME;
        }
        // Fragments can overlap in time.  Discard overlapping frames after
        // decoding.
        if (prev_dts >= dts)
            index_entry_flags |= AVINDEX_DISCARD_FRAME;

        sti->index_entries[index_entry_pos].pos   = offset;
        sti->index_entries[index_entry_pos].timestamp = dts;
        sti->index_entries[index_entry_pos].size  = sample_size;
        sti->index_entries[index_entry_pos].min_distance = distance;
        sti->index_entries[index_entry_pos].flags = index_entry_flags;

        sc->ctts_data[index_entry_pos].count = 1;
        sc->ctts_data[index_entry_pos].duration = ctts_duration;
        index_entry_pos++;

        av_log(c->fc, AV_LOG_TRACE, "AVIndex stream %d, sample %d, offset %"PRIx64", dts %"PRId64", "
                "size %u, distance %d, keyframe %d\n", st->index,
                index_entry_pos, offset, dts, sample_size, distance, keyframe);
        distance++;
        if (av_sat_add64(dts, sample_duration) != dts + (uint64_t)sample_duration)
            return AVERROR_INVALIDDATA;
        if (!sample_size)
            return AVERROR_INVALIDDATA;
        dts += sample_duration;
        offset += sample_size;
        sc->data_size += sample_size;

        if (sample_duration <= INT64_MAX - sc->duration_for_fps &&
            1 <= INT_MAX - sc->nb_frames_for_fps
        ) {
            sc->duration_for_fps += sample_duration;
            sc->nb_frames_for_fps ++;
        }
    }
    if (frag_stream_info)
        frag_stream_info->next_trun_dts = dts + sc->time_offset;
    if (i < entries) {
        // EOF found before reading all entries.  Fix the hole this would
        // leave in index_entries and ctts_data
        int gap = entries - i;
        memmove(sti->index_entries + index_entry_pos,
                sti->index_entries + index_entry_pos + gap,
                sizeof(*sti->index_entries) *
                (sti->nb_index_entries - (index_entry_pos + gap)));
        memmove(sc->ctts_data + index_entry_pos,
                sc->ctts_data + index_entry_pos + gap,
                sizeof(*sc->ctts_data) *
                (sc->ctts_count - (index_entry_pos + gap)));

        sti->nb_index_entries -= gap;
        sc->ctts_count -= gap;
        if (index_entry_pos < sc->current_sample) {
            sc->current_sample -= gap;
        }
        entries = i;
    }

    // The end of this new fragment may overlap in time with the start
    // of the next fragment in index_entries. Mark the samples in the next
    // fragment that overlap with AVINDEX_DISCARD_FRAME
    prev_dts = AV_NOPTS_VALUE;
    if (index_entry_pos > 0)
        prev_dts = sti->index_entries[index_entry_pos-1].timestamp;
    for (int i = index_entry_pos; i < sti->nb_index_entries; i++) {
        if (prev_dts < sti->index_entries[i].timestamp)
            break;
        sti->index_entries[i].flags |= AVINDEX_DISCARD_FRAME;
    }

    // If a hole was created to insert the new index_entries into,
    // the index_entry recorded for all subsequent moof must
    // be incremented by the number of entries inserted.
    fix_frag_index_entries(&c->frag_index, next_frag_index,
                           frag->track_id, entries);

    if (pb->eof_reached) {
        av_log(c->fc, AV_LOG_WARNING, "reached eof, corrupted TRUN atom\n");
        return AVERROR_EOF;
    }

    frag->implicit_offset = offset;

    sc->track_end = dts + sc->time_offset;
    if (st->duration < sc->track_end)
        st->duration = sc->track_end;

    return 0;
}

Project: FFmpeg
File: mov.c

static void fix_index_entry_timestamps(AVStream* st, int end_index, int64_t end_ts,
                                       int64_t* frame_duration_buffer,
                                       int frame_duration_buffer_size) {
    FFStream *const sti = ffstream(st);
    int i = 0;
    av_assert0(end_index >= 0 && end_index <= sti->nb_index_entries);
    for (i = 0; i < frame_duration_buffer_size; i++) {
        end_ts -= frame_duration_buffer[frame_duration_buffer_size - 1 - i];
        sti->index_entries[end_index - 1 - i].timestamp = end_ts;
    }
}

Project: FFmpeg
File: mov.c

static int mov_read_sdtp(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
    AVStream *st;
    MOVStreamContext *sc;
    int64_t i, 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 = atom.size - 4;

    av_log(c->fc, AV_LOG_TRACE, "track[%u].sdtp.entries = %" PRId64 "\n",
           c->fc->nb_streams - 1, entries);

    if (sc->sdtp_data)
        av_log(c->fc, AV_LOG_WARNING, "Duplicated SDTP atom\n");
    av_freep(&sc->sdtp_data);
    sc->sdtp_count = 0;

    sc->sdtp_data = av_malloc(entries);
    if (!sc->sdtp_data)
        return AVERROR(ENOMEM);

    for (i = 0; i < entries && !pb->eof_reached; i++)
        sc->sdtp_data[i] = avio_r8(pb);
    sc->sdtp_count = i;

    return 0;
}

Project: FFmpeg
File: mov.c

static int mov_realloc_extradata(AVCodecParameters *par, MOVAtom atom)
{
    int err = 0;
    uint64_t size = (uint64_t)par->extradata_size + atom.size + 8 + AV_INPUT_BUFFER_PADDING_SIZE;
    if (size > INT_MAX || (uint64_t)atom.size > INT_MAX)
        return AVERROR_INVALIDDATA;
    if ((err = av_reallocp(&par->extradata, size)) < 0) {
        par->extradata_size = 0;
        return err;
    }
    par->extradata_size = size - AV_INPUT_BUFFER_PADDING_SIZE;
    return 0;
}

Project: FFmpeg
File: mov.c

static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
    int version, offset_size, length_size, base_offset_size, index_size;
    int item_count, extent_count;
    uint64_t base_offset, extent_offset, extent_length;
    uint8_t value;

    if (!c->is_still_picture_avif) {
        // * For non-avif, we simply ignore the iloc box.
        // * For animated avif, we don't care about the iloc box as all the
        //   necessary information can be found in the moov box.
        return 0;
    }

    if (c->fc->nb_streams) {
        av_log(c->fc, AV_LOG_INFO, "Duplicate iloc box found\n");
        return 0;
    }

    version = avio_r8(pb);
    avio_rb24(pb);  // flags.

    value = avio_r8(pb);
    offset_size = (value >> 4) & 0xF;
    length_size = value & 0xF;
    value = avio_r8(pb);
    base_offset_size = (value >> 4) & 0xF;
    index_size = !version ? 0 : (value & 0xF);
    if (index_size) {
        av_log(c->fc, AV_LOG_ERROR, "iloc: index_size != 0 not supported.\n");
        return AVERROR_PATCHWELCOME;
    }
    item_count = (version < 2) ? avio_rb16(pb) : avio_rb32(pb);

    c->avif_info = av_malloc_array(item_count, sizeof(*c->avif_info));
    if (!c->avif_info)
        return AVERROR(ENOMEM);
    c->avif_info_size = item_count;

    for (int i = 0; i < item_count; i++) {
        int item_id = (version < 2) ? avio_rb16(pb) : avio_rb32(pb);
        if (avio_feof(pb))
            return AVERROR_INVALIDDATA;
        c->avif_info[i].item_id = item_id;

        if (version > 0)
            avio_rb16(pb);  // construction_method.
        avio_rb16(pb);  // data_reference_index.
        if (rb_size(pb, &base_offset, base_offset_size) < 0)
            return AVERROR_INVALIDDATA;
        extent_count = avio_rb16(pb);
        if (extent_count > 1) {
            // For still AVIF images, we only support one extent item.
            av_log(c->fc, AV_LOG_ERROR, "iloc: extent_count > 1 not supported.\n");
            return AVERROR_PATCHWELCOME;
        }
        for (int j = 0; j < extent_count; j++) {
            if (rb_size(pb, &extent_offset, offset_size) < 0 ||
                rb_size(pb, &extent_length, length_size) < 0)
                return AVERROR_INVALIDDATA;
            c->avif_info[i].extent_length = extent_length;
            c->avif_info[i].extent_offset = base_offset + extent_offset;
        }
    }

    return atom.size;
}

Project: FFmpeg
File: mov.c

static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
    AVStream *st;
    MOVStreamContext *sc;
    unsigned int i, entries, alloc_size = 0;
    int64_t duration = 0;
    int64_t total_sample_count = 0;
    int64_t current_dts = 0;
    int64_t corrected_dts = 0;

    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);

    av_log(c->fc, AV_LOG_TRACE, "track[%u].stts.entries = %u\n",
            c->fc->nb_streams-1, entries);

    if (sc->stts_data)
        av_log(c->fc, AV_LOG_WARNING, "Duplicated STTS atom\n");
    av_freep(&sc->stts_data);
    sc->stts_count = 0;
    if (entries >= INT_MAX / sizeof(*sc->stts_data))
        return AVERROR(ENOMEM);

    for (i = 0; i < entries && !pb->eof_reached; i++) {
        unsigned int sample_duration;
        unsigned int sample_count;
        unsigned int min_entries = FFMIN(FFMAX(i + 1, 1024 * 1024), entries);
        MOVStts *stts_data = av_fast_realloc(sc->stts_data, &alloc_size,
                                             min_entries * sizeof(*sc->stts_data));
        if (!stts_data) {
            av_freep(&sc->stts_data);
            sc->stts_count = 0;
            return AVERROR(ENOMEM);
        }
        sc->stts_count = min_entries;
        sc->stts_data = stts_data;

        sample_count    = avio_rb32(pb);
        sample_duration = avio_rb32(pb);

        sc->stts_data[i].count= sample_count;
        sc->stts_data[i].duration= sample_duration;

        av_log(c->fc, AV_LOG_TRACE, "sample_count=%u, sample_duration=%u\n",
                sample_count, sample_duration);

        /* STTS sample offsets are uint32 but some files store it as int32
         * with negative values used to correct DTS delays.
           There may be abnormally large values as well. */
        if (sample_duration > c->max_stts_delta) {
            // assume high delta is a correction if negative when cast as int32
            int32_t delta_magnitude = (int32_t)sample_duration;
            av_log(c->fc, AV_LOG_WARNING, "Too large sample offset %u in stts entry %u with count %u in st:%d. Clipping to 1.\n",
                   sample_duration, i, sample_count, st->index);
            sc->stts_data[i].duration = 1;
            corrected_dts += (delta_magnitude < 0 ? (int64_t)delta_magnitude : 1) * sample_count;
        } else {
            corrected_dts += sample_duration * sample_count;
        }

        current_dts += sc->stts_data[i].duration * sample_count;

        if (current_dts > corrected_dts) {
            int64_t drift = (current_dts - corrected_dts)/FFMAX(sample_count, 1);
            uint32_t correction = (sc->stts_data[i].duration > drift) ? drift : sc->stts_data[i].duration - 1;
            current_dts -= correction * sample_count;
            sc->stts_data[i].duration -= correction;
        }

        duration+=(int64_t)sc->stts_data[i].duration*(uint64_t)sc->stts_data[i].count;
        total_sample_count+=sc->stts_data[i].count;
    }

    sc->stts_count = i;

    if (duration > 0 &&
        duration <= INT64_MAX - sc->duration_for_fps &&
        total_sample_count <= INT_MAX - sc->nb_frames_for_fps) {
        sc->duration_for_fps  += duration;
        sc->nb_frames_for_fps += total_sample_count;
    }

    if (pb->eof_reached) {
        av_log(c->fc, AV_LOG_WARNING, "reached eof, corrupted STTS atom\n");
        return AVERROR_EOF;
    }

    st->nb_frames= total_sample_count;
    if (duration)
        st->duration= FFMIN(st->duration, duration);

    // All samples have zero duration. They have higher chance be chose by
    // mov_find_next_sample, which leads to seek again and again.
    //
    // It's AVERROR_INVALIDDATA actually, but such files exist in the wild.
    // So only mark data stream as discarded for safety.
    if (!duration && sc->stts_count &&
            st->codecpar->codec_type == AVMEDIA_TYPE_DATA) {
        av_log(c->fc, AV_LOG_WARNING,
               "All samples in data stream index:id [%d:%d] have zero "
               "duration, stream set to be discarded by default. Override "
               "using AVStream->discard or -discard for ffmpeg command.\n",
               st->index, st->id);
        st->discard = AVDISCARD_ALL;
    }
    sc->track_end = duration;
    return 0;
}

Project: FFmpeg
File: mov.c

static int mov_seek_fragment(AVFormatContext *s, AVStream *st, int64_t timestamp)
{
    MOVContext *mov = s->priv_data;
    int index;

    if (!mov->frag_index.complete)
        return 0;

    index = search_frag_timestamp(s, &mov->frag_index, st, timestamp);
    if (index < 0)
        index = 0;
    if (!mov->frag_index.item[index].headers_read)
        return mov_switch_root(s, -1, index);
    if (index + 1 < mov->frag_index.nb_items)
        mov->next_root_atom = mov->frag_index.item[index + 1].moof_offset;

    return 0;
}

Project: FFmpeg
File: mov.c

static int mov_read_aclr(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
    int ret = 0;
    int length = 0;
    uint64_t original_size;
    if (c->fc->nb_streams >= 1) {
        AVCodecParameters *par = c->fc->streams[c->fc->nb_streams-1]->codecpar;
        if (par->codec_id == AV_CODEC_ID_H264)
            return 0;
        if (atom.size == 16) {
            original_size = par->extradata_size;
            ret = mov_realloc_extradata(par, atom);
            if (!ret) {
                length =  mov_read_atom_into_extradata(c, pb, atom, par, par->extradata + original_size);
                if (length == atom.size) {
                    const uint8_t range_value = par->extradata[original_size + 19];
                    switch (range_value) {
                    case 1:
                        par->color_range = AVCOL_RANGE_MPEG;
                        break;
                    case 2:
                        par->color_range = AVCOL_RANGE_JPEG;
                        break;
                    default:
                        av_log(c->fc, AV_LOG_WARNING, "ignored unknown aclr value (%d)\n", range_value);
                        break;
                    }
                    ff_dlog(c->fc, "color_range: %d\n", par->color_range);
                } else {
                  /* For some reason the whole atom was not added to the extradata */
                  av_log(c->fc, AV_LOG_ERROR, "aclr not decoded - incomplete atom\n");
                }
            } else {
                av_log(c->fc, AV_LOG_ERROR, "aclr not decoded - unable to add atom to extradata\n");
            }
        } else {
            av_log(c->fc, AV_LOG_WARNING, "aclr not decoded - unexpected size %"PRId64"\n", atom.size);
        }
    }

    return ret;
}