Repository: opencv/opencv
File: modules/videoio/src/cap_ffmpeg_impl.hpp (C++)

Code before:
                    min_start_avtb = ic->start_time;
                }

                // Check stream start_time
                AVStream* st = ic->streams[video_stream];
                if (st->start_time != AV_NOPTS_VALUE_)
                {
                    int64_t s = to_avtb(st->start_time, st->time_base);
                    if (s < min_start_avtb) min_start_avtb = s;
                }

                // Check first observed timestamp (PTS preferred, else DTS from frame 0)
                int64_t first_ts_stream = picture_pts;
                if (first_ts_stream == AV_NOPTS_VALUE_ && dts != AV_NOPTS_VALUE_)
                {
                    first_ts_stream = dts;
                }
                if (first_ts_stream != AV_NOPTS_VALUE_)
                {
                    int64_t t = to_avtb(first_ts_stream, st->time_base);
                    if (t < min_start_avtb) min_start_avtb = t;
                }

                // Compute offset to shift timestamps to zero
                if (min_start_avtb != INT64_MAX) {
                    ts_offset_avtb = -min_start_avtb;
                } else {
                    ts_offset_avtb = 0;
                }
                ts_offset_decided = true;
            }

            // Apply normalization to picture_pts
            if (picture_pts != AV_NOPTS_VALUE_)
            {
                int64_t t = to_avtb(picture_pts, video_st->time_base);
                t += ts_offset_avtb;
                picture_pts = from_avtb(t, video_st->time_base);
            }

            // Also normalize dts
            if (dts != AV_NOPTS_VALUE_)
            {
                int64_t t = to_avtb(dts, video_st->time_base);
                t += ts_offset_avtb;
                dts = from_avtb(t, video_st->time_base);
            }



#if LIBAVCODEC_BUILD >= CALC_FFMPEG_VERSION(54, 1, 0) || LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(52, 111, 0)

Review comment (suggestion):
`if (min_start_avtb < 0)` is preferable to keep original timestamp on "non-issue" videos with all non-negative timestamps.

Code after:
#endif
        if (ret >= 0) {
            valid = true;
        } else if (ret == AVERROR(EAGAIN)) {
            continue;
        }
        else
        {
            if (++cur_decode_attempts > max_decode_attempts)
            {
                CV_LOG_WARNING(NULL,
                    "frame decode max attempts exceeded, try to increase attempt "
                    "limit by setting environment variable OPENCV_FFMPEG_DECODE_ATTEMPTS "
                    "(current value is " << max_decode_attempts << ")");
                break;
            }
        }
    }

    if (valid) {
        if (picture_pts == AV_NOPTS_VALUE_) {
            int64_t dts = 0;
            if (!rawMode) {
                picture_pts = (picture->CV_FFMPEG_PTS_FIELD != AV_NOPTS_VALUE_)
                                ? picture->CV_FFMPEG_PTS_FIELD
                                : picture->pkt_dts;
                if (frame_number == 0) dts = picture->pkt_dts;
            } else {
                const AVPacket& packet_raw = (packet.data != 0) ? packet : packet_filtered;
                picture_pts = (packet_raw.pts != AV_NOPTS_VALUE_)
                                ? packet_raw.pts
                                : packet_raw.dts;
                if (frame_number == 0) dts = packet_raw.dts;
            }

            // Decide timestamp offset once on first frame to normalize all timestamps to start at zero.
            // This handles videos with negative DTS values (e.g., from B-frame reordering) or non-zero
            // start_time. Similar to FFmpeg's -avoid_negative_ts make_zero option.
            if (!ts_offset_decided)
            {
                int64_t min_start_avtb = INT64_MAX;

                // Check container start_time (already in AV_TIME_BASE units)
                if (ic && ic->start_time != AV_NOPTS_VALUE_)
                {
                    min_start_avtb = ic->start_time;
                }

                // Check stream start_time
                AVStream* st = ic->streams[video_stream];
                if (st->start_time != AV_NOPTS_VALUE_)