#include "media/mkv_timed_range.hpp"
#include "media/ffmpeg_raii.hpp"
#include "media/pcm_normalize.hpp"

#include <algorithm>
#include <cstdint>
#include <cstring>
#include <filesystem>
#include <limits>
#include <optional>
#include <sstream>
#include <vector>

#ifdef SMARTCUT_HAS_FFMPEG
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
}
#endif

namespace smartcut::media {
#ifdef SMARTCUT_HAS_FFMPEG
namespace {
struct TimedRange {
  int video_stream{-1};
  std::int64_t start_us{AV_NOPTS_VALUE};
  std::int64_t end_us{AV_NOPTS_VALUE};
  bool first_key{};
};

std::int64_t packet_timestamp(const AVPacket* packet) {
  return packet->pts != AV_NOPTS_VALUE ? packet->pts : packet->dts;
}

std::int64_t packet_start_us(const AVPacket* packet, const AVStream* stream) {
  const auto timestamp = packet_timestamp(packet);
  return timestamp == AV_NOPTS_VALUE ? AV_NOPTS_VALUE : av_rescale_q(timestamp, stream->time_base, AV_TIME_BASE_Q);
}

std::int64_t packet_decode_us(const AVPacket* packet, const AVStream* stream) {
  if (packet->dts == AV_NOPTS_VALUE) return packet_start_us(packet, stream);
  return av_rescale_q(packet->dts, stream->time_base, AV_TIME_BASE_Q);
}

std::int64_t packet_end_us(const AVPacket* packet, const AVStream* stream) {
  const auto start = packet_start_us(packet, stream);
  if (start == AV_NOPTS_VALUE) return AV_NOPTS_VALUE;
  std::int64_t duration = 1;
  if (packet->duration > 0) {
    duration = av_rescale_q(packet->duration, stream->time_base, AV_TIME_BASE_Q);
  } else if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && stream->codecpar->frame_size > 0 && stream->codecpar->sample_rate > 0) {
    duration = av_rescale_q(stream->codecpar->frame_size, AVRational{1, stream->codecpar->sample_rate}, AV_TIME_BASE_Q);
  }
  return start + std::max<std::int64_t>(duration, 1);
}

bool is_text_subtitle(AVCodecID codec) {
  return codec == AV_CODEC_ID_SUBRIP || codec == AV_CODEC_ID_ASS || codec == AV_CODEC_ID_WEBVTT ||
         codec == AV_CODEC_ID_TEXT || codec == AV_CODEC_ID_MOV_TEXT;
}

bool is_attached_picture(const AVStream* stream) {
  return stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && (stream->disposition & AV_DISPOSITION_ATTACHED_PIC) != 0;
}

bool intermediate_stream_supported(const AVStream* stream) {
  const auto type = stream->codecpar->codec_type;
  return type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO ||
         type == AVMEDIA_TYPE_SUBTITLE || type == AVMEDIA_TYPE_ATTACHMENT;
}

void supply_bitmap_subtitle_dimensions(AVCodecParameters* parameters,
                                       const AVFormatContext* source,
                                       int video_stream) {
  if (!parameters || !source || video_stream < 0 ||
      static_cast<unsigned>(video_stream) >= source->nb_streams ||
      parameters->codec_type != AVMEDIA_TYPE_SUBTITLE ||
      parameters->codec_id != AV_CODEC_ID_HDMV_PGS_SUBTITLE ||
      (parameters->width > 0 && parameters->height > 0)) return;
  // Older Matroska PGS tracks often omit canvas dimensions because each PGS
  // display set carries them. libavformat requires container dimensions when
  // remuxing, so inherit the associated video canvas without touching payload.
  parameters->width = source->streams[video_stream]->codecpar->width;
  parameters->height = source->streams[video_stream]->codecpar->height;
}

bool open_source(const std::string& path, AVFormatContext** source) {
  return avformat_open_input(source, path.c_str(), nullptr, nullptr) >= 0 &&
         avformat_find_stream_info(*source, nullptr) >= 0;
}

bool packet_has_random_access_nal(const AVPacket* packet, const AVCodecParameters* parameters) {
  if (!packet || !parameters || (packet->flags & AV_PKT_FLAG_KEY) == 0) return false;
  // FFmpeg's H.264/HEVC parsers mark packets as keyframes only at usable
  // random-access access units (H.264 IDR/recovery points and HEVC IRAP).
  // Trust that parsed classification: some Matroska tracks carry length-prefix
  // metadata that the lightweight scanner below cannot walk even though the
  // packet is a valid clean random-access point.
  if (parameters->codec_id == AV_CODEC_ID_H264 || parameters->codec_id == AV_CODEC_ID_HEVC) return true;
  if (parameters->codec_id != AV_CODEC_ID_H264 && parameters->codec_id != AV_CODEC_ID_HEVC) return true;
  const auto* data = reinterpret_cast<const std::uint8_t*>(packet->data);
  const auto size = static_cast<std::size_t>(packet->size);
  const auto random_access_type = [&](std::size_t offset) {
    if (offset >= size) return false;
    if (parameters->codec_id == AV_CODEC_ID_H264) return (data[offset] & 0x1fU) == 5U;
    const auto type = (data[offset] >> 1U) & 0x3fU;
    // CRA_NUT (21) is a valid clean random-access entry when RASL pictures
    // preceding its presentation timestamp are discarded. Timed copying does
    // that naturally by selecting packets on presentation time.
    return type >= 16U && type <= 21U;
  };
  bool annex_b = false;
  for (std::size_t i = 0; i + 3 < size; ++i) {
    if (data[i] == 0 && data[i + 1] == 0 && (data[i + 2] == 1 || (data[i + 2] == 0 && data[i + 3] == 1))) {
      annex_b = true;
      const auto offset = i + (data[i + 2] == 1 ? 3U : 4U);
      if (random_access_type(offset)) return true;
    }
  }
  if (annex_b) return false;
  std::size_t length_size = 4;
  if (parameters->extradata && parameters->extradata_size > 5 && parameters->extradata[0] == 1) {
    if (parameters->codec_id == AV_CODEC_ID_H264) length_size = static_cast<std::size_t>((parameters->extradata[4] & 3U) + 1U);
    else if (parameters->extradata_size > 21) length_size = static_cast<std::size_t>((parameters->extradata[21] & 3U) + 1U);
  }
  for (std::size_t cursor = 0; cursor + length_size <= size;) {
    std::size_t bytes = 0;
    for (std::size_t i = 0; i < length_size; ++i) bytes = (bytes << 8U) | data[cursor + i];
    cursor += length_size;
    if (bytes == 0 || cursor + bytes > size) break;
    if (random_access_type(cursor)) return true;
    cursor += bytes;
  }
  return false;
}

bool constant_frame_timing(const AVStream* stream, AVRational& frame_rate,
                           std::int64_t& first_pts) {
  if (!stream || stream->r_frame_rate.num <= 0 || stream->r_frame_rate.den <= 0 ||
      stream->avg_frame_rate.num <= 0 || stream->avg_frame_rate.den <= 0 ||
      av_cmp_q(stream->r_frame_rate, stream->avg_frame_rate) != 0 ||
      stream->time_base.num <= 0 || stream->time_base.den <= 0 ||
      stream->start_time == AV_NOPTS_VALUE) return false;
  frame_rate = stream->avg_frame_rate;
  first_pts = stream->start_time;
  return true;
}

std::int64_t frame_pts(std::size_t frame, const AVStream* stream,
                       AVRational frame_rate, std::int64_t first_pts) {
  // Container time bases often cannot represent an exact frame duration. Use
  // the lower edge of the target frame interval so a rounded-up end point does
  // not accidentally include the first packet of the following GOP.
  return first_pts + av_rescale_q_rnd(static_cast<std::int64_t>(frame),
                                     AVRational{frame_rate.den, frame_rate.num},
                                     stream->time_base, AV_ROUND_DOWN);
}

std::optional<std::size_t> frame_for_pts(std::int64_t pts, const AVStream* stream,
                                         AVRational frame_rate, std::int64_t first_pts) {
  if (pts == AV_NOPTS_VALUE || pts < first_pts) return std::nullopt;
  const auto frame = av_rescale_q_rnd(pts - first_pts, stream->time_base,
                                     AVRational{frame_rate.den, frame_rate.num},
                                     AV_ROUND_NEAR_INF);
  return frame < 0 ? std::nullopt : std::optional<std::size_t>(static_cast<std::size_t>(frame));
}

bool determine_constant_frame_range(AVFormatContext* source, std::size_t first,
                                    std::size_t end, TimedRange& range,
                                    bool require_key) {
  if (!source || end <= first) return false;
  for (unsigned i = 0; i < source->nb_streams; ++i) {
    if (source->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
        !is_attached_picture(source->streams[i])) { range.video_stream = static_cast<int>(i); break; }
  }
  if (range.video_stream < 0) return false;
  const auto* stream = source->streams[range.video_stream];
  AVRational frame_rate{}; std::int64_t first_pts = AV_NOPTS_VALUE;
  if (!constant_frame_timing(stream, frame_rate, first_pts)) return false;
  const auto start_pts = frame_pts(first, stream, frame_rate, first_pts);
  const auto end_pts = frame_pts(end, stream, frame_rate, first_pts);
  range.start_us = av_rescale_q(start_pts, stream->time_base, AV_TIME_BASE_Q);
  range.end_us = av_rescale_q(end_pts, stream->time_base, AV_TIME_BASE_Q);
  if (!require_key) { range.first_key = true; return range.end_us > range.start_us; }
  constexpr std::size_t seek_preroll_frames = 512;
  const auto seek_frame = first > seek_preroll_frames ? first - seek_preroll_frames : std::size_t{0};
  const auto seek_pts = frame_pts(seek_frame, stream, frame_rate, first_pts);
  if (av_seek_frame(source, range.video_stream, seek_pts, AVSEEK_FLAG_BACKWARD) < 0) return false;
  avformat_flush(source);
  AVPacket* packet = av_packet_alloc();
  std::size_t examined = 0;
  while (packet && examined < seek_preroll_frames * 2 && av_read_frame(source, packet) >= 0) {
    if (packet->stream_index == range.video_stream) {
      ++examined;
      const auto pts = packet_timestamp(packet);
      const auto mapped = frame_for_pts(pts, stream, frame_rate, first_pts);
      if (mapped && *mapped == first) {
        range.first_key = range.first_key || packet_has_random_access_nal(packet, stream->codecpar);
      } else if (mapped && *mapped > first) {
        av_packet_unref(packet);
        break;
      }
    }
    av_packet_unref(packet);
  }
  av_packet_free(&packet);
  return range.first_key && range.end_us > range.start_us;
}

bool seek_to_range_start(AVFormatContext* source, const TimedRange& range) {
  if (!source || range.video_stream < 0 ||
      static_cast<unsigned>(range.video_stream) >= source->nb_streams) return false;
  const auto* stream = source->streams[range.video_stream];
  auto target = av_rescale_q(range.start_us, AV_TIME_BASE_Q, stream->time_base);
  if (stream->start_time != AV_NOPTS_VALUE && target <= stream->start_time) return true;
  const auto overlap_margin = av_rescale_q(10, AVRational{1, 1}, stream->time_base);
  if (stream->start_time != AV_NOPTS_VALUE) target = std::max(stream->start_time, target - overlap_margin);
  else target -= overlap_margin;
  if (av_seek_frame(source, range.video_stream, target, AVSEEK_FLAG_BACKWARD) < 0) return false;
  avformat_flush(source);
  return true;
}

bool determine_range(AVFormatContext* source, std::size_t first, std::size_t end, TimedRange& range,
                     bool require_key = true) {
  if (determine_constant_frame_range(source, first, end, range, require_key)) return true;
  range = {};
  if (end <= first) return false;
  for (unsigned i = 0; i < source->nb_streams; ++i) {
    if (source->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && !is_attached_picture(source->streams[i])) {
      range.video_stream = static_cast<int>(i);
      break;
    }
  }
  if (range.video_stream < 0) return false;
  const auto* stream = source->streams[range.video_stream];
  const bool strict_random_access = stream->codecpar->codec_id == AV_CODEC_ID_H264 ||
                                    stream->codecpar->codec_id == AV_CODEC_ID_HEVC;
  const auto* codec = ffmpeg::preferred_video_decoder(stream->codecpar->codec_id);
  AVCodecContext* decoder = codec ? avcodec_alloc_context3(codec) : nullptr;
  AVPacket* packet = av_packet_alloc();
  AVFrame* frame = av_frame_alloc();
  if (!decoder || !packet || !frame || avcodec_parameters_to_context(decoder, stream->codecpar) < 0 ||
      avcodec_open2(decoder, codec, nullptr) < 0) {
    av_frame_free(&frame); av_packet_free(&packet); avcodec_free_context(&decoder); return false;
  }
  std::vector<std::int64_t> key_pts;
  std::size_t video_index = 0;
  std::int64_t previous_us = AV_NOPTS_VALUE;
  std::int64_t final_duration_us = 0;
  auto receive = [&] {
    while (avcodec_receive_frame(decoder, frame) >= 0) {
      const auto timestamp = frame->best_effort_timestamp != AV_NOPTS_VALUE ? frame->best_effort_timestamp : frame->pts;
      const auto start_us = timestamp == AV_NOPTS_VALUE ? AV_NOPTS_VALUE : av_rescale_q(timestamp, stream->time_base, AV_TIME_BASE_Q);
      if (video_index == first) {
        range.start_us = start_us;
        range.first_key = std::find(key_pts.begin(), key_pts.end(), timestamp) != key_pts.end() ||
                          (!strict_random_access && (frame->flags & AV_FRAME_FLAG_KEY) != 0);
      }
      if (video_index == end) range.end_us = start_us;
      if (previous_us != AV_NOPTS_VALUE && start_us != AV_NOPTS_VALUE && start_us > previous_us)
        final_duration_us = start_us - previous_us;
      previous_us = start_us;
      ++video_index;
      av_frame_unref(frame);
    }
  };
  while (av_read_frame(source, packet) >= 0) {
    if (packet->stream_index == range.video_stream) {
      if (packet_has_random_access_nal(packet, stream->codecpar) && packet->pts != AV_NOPTS_VALUE) key_pts.push_back(packet->pts);
      if (avcodec_send_packet(decoder, packet) >= 0) receive();
    }
    av_packet_unref(packet);
    if (range.end_us != AV_NOPTS_VALUE) break;
  }
  if (range.end_us == AV_NOPTS_VALUE) { avcodec_send_packet(decoder, nullptr); receive(); }
  if (end == video_index && previous_us != AV_NOPTS_VALUE) {
    if (final_duration_us <= 0 && stream->avg_frame_rate.num > 0)
      final_duration_us = av_rescale_q(1, AVRational{stream->avg_frame_rate.den, stream->avg_frame_rate.num}, AV_TIME_BASE_Q);
    range.end_us = previous_us + std::max<std::int64_t>(final_duration_us, 1);
  }
  av_frame_free(&frame); av_packet_free(&packet); avcodec_free_context(&decoder);
  return first < video_index && end <= video_index && range.start_us != AV_NOPTS_VALUE &&
         range.end_us != AV_NOPTS_VALUE && range.end_us > range.start_us && (!require_key || range.first_key);
}

bool selected_packet(const AVPacket* packet, const AVFormatContext* source, const TimedRange& range,
                     std::size_t& video_index, std::vector<std::int64_t>& last_start_us,
                     bool& split_subtitle) {
  const auto* stream = source->streams[packet->stream_index];
  auto start = packet_start_us(packet, stream);
  if (start != AV_NOPTS_VALUE) last_start_us[static_cast<std::size_t>(packet->stream_index)] = start;
  else start = last_start_us[static_cast<std::size_t>(packet->stream_index)];
  if (packet->stream_index == range.video_stream) {
    const bool selected = start >= range.start_us && start < range.end_us;
    ++video_index;
    return selected;
  }
  if (stream->codecpar->codec_type == AVMEDIA_TYPE_ATTACHMENT) return false;
  if (start == AV_NOPTS_VALUE) return false;
  auto duration = packet->duration > 0 ? av_rescale_q(packet->duration, stream->time_base, AV_TIME_BASE_Q) : 1;
  if (packet->duration <= 0 && stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
      stream->codecpar->frame_size > 0 && stream->codecpar->sample_rate > 0)
    duration = av_rescale_q(stream->codecpar->frame_size,
                            AVRational{1, stream->codecpar->sample_rate}, AV_TIME_BASE_Q);
  const auto finish = start + std::max<std::int64_t>(duration, 1);
  const bool overlap = finish > range.start_us && start < range.end_us;
  split_subtitle = overlap && stream->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE &&
                   is_text_subtitle(stream->codecpar->codec_id) &&
                   (start < range.start_us || finish > range.end_us);
  return overlap;
}

bool reopen(const std::string& path, AVFormatContext** source) {
  avformat_close_input(source);
  return open_source(path, source);
}

void copy_stream_attributes(AVStream* output, const AVStream* input) {
  output->disposition = input->disposition;
  output->avg_frame_rate = input->avg_frame_rate;
  output->r_frame_rate = input->r_frame_rate;
  output->sample_aspect_ratio = input->sample_aspect_ratio;
  av_dict_copy(&output->metadata, input->metadata, 0);
}

void set_navigation_metadata(AVStream* output, const AVStream* input, std::size_t frame_count) {
  if (!output || !input || input->codecpar->codec_type != AVMEDIA_TYPE_VIDEO || is_attached_picture(input)) return;
  const auto count = std::to_string(frame_count);
  const auto rate_num = std::to_string(input->avg_frame_rate.num);
  const auto rate_den = std::to_string(input->avg_frame_rate.den);
  av_dict_set(&output->metadata, "SMARTCUT_FRAME_COUNT", count.c_str(), 0);
  av_dict_set(&output->metadata, "SMARTCUT_FRAME_RATE_NUM", rate_num.c_str(), 0);
  av_dict_set(&output->metadata, "SMARTCUT_FRAME_RATE_DEN", rate_den.c_str(), 0);
}

bool metadata_equal(const AVStream* source, const AVStream* output) {
  if (source->codecpar->codec_type != output->codecpar->codec_type ||
      !matroska_codec_equivalent(source->codecpar, output->codecpar) ||
      source->disposition != output->disposition ||
      source->codecpar->extradata_size != output->codecpar->extradata_size) return false;
  if (source->codecpar->extradata_size > 0 &&
      std::memcmp(source->codecpar->extradata, output->codecpar->extradata,
                  static_cast<std::size_t>(source->codecpar->extradata_size)) != 0) return false;
  for (const char* key : {"title", "language", "filename", "mimetype"}) {
    const auto* expected = av_dict_get(source->metadata, key, nullptr, 0);
    const auto* actual = av_dict_get(output->metadata, key, nullptr, 0);
    if (std::strcmp(key, "language") == 0) {
      const auto unspecified = [](const AVDictionaryEntry* entry) {
        return entry == nullptr || std::strcmp(entry->value, "und") == 0;
      };
      if (unspecified(expected) && unspecified(actual)) continue;
    }
    if ((expected == nullptr) != (actual == nullptr)) return false;
    if (expected && std::strcmp(expected->value, actual->value) != 0) return false;
  }
  return true;
}

bool packet_payloads_equal(const std::vector<std::vector<std::uint8_t>>& expected,
                           const std::vector<std::vector<std::uint8_t>>& actual,
                           bool allow_repacketization,
                           bool allow_codec_boundary_trim = false) {
  if (!allow_repacketization) return expected == actual;
  std::size_t expected_size = 0;
  std::size_t actual_size = 0;
  for (const auto& packet : expected) expected_size += packet.size();
  for (const auto& packet : actual) actual_size += packet.size();
  std::vector<std::uint8_t> expected_bytes;
  std::vector<std::uint8_t> actual_bytes;
  expected_bytes.reserve(expected_size);
  actual_bytes.reserve(actual_size);
  for (const auto& packet : expected) expected_bytes.insert(expected_bytes.end(), packet.begin(), packet.end());
  for (const auto& packet : actual) actual_bytes.insert(actual_bytes.end(), packet.begin(), packet.end());
  if (expected_bytes == actual_bytes) return true;
  // TrueHD packets between a cut and the next major-sync access unit are not
  // independently decodable. The Matroska muxer correctly discards that small
  // leading fragment. Accept only an otherwise byte-identical contiguous
  // payload with at most one bounded codec access unit removed at either edge.
  if (!allow_codec_boundary_trim || actual_bytes.empty() || actual_bytes.size() > expected_bytes.size() ||
      expected_bytes.size() - actual_bytes.size() > 64U * 1024U) return false;
  const auto found = std::search(expected_bytes.begin(), expected_bytes.end(),
                                 actual_bytes.begin(), actual_bytes.end());
  return found != expected_bytes.end();
}

class RangeEndTracker {
 public:
  RangeEndTracker(const AVFormatContext* source, std::int64_t end_us)
      : source_(source), end_us_(end_us), consecutive_(source->nb_streams, 0),
        required_(source->nb_streams, 0) {
    for (unsigned index = 0; index < source->nb_streams; ++index) {
      const auto* codec = source->streams[index]->codecpar;
      if (codec->codec_type == AVMEDIA_TYPE_AUDIO) required_[index] = 2;
      if (codec->codec_type == AVMEDIA_TYPE_VIDEO && !is_attached_picture(source->streams[index]))
        required_[index] = static_cast<std::size_t>(std::max(codec->video_delay + 4, 4));
    }
  }

  void observe(const AVPacket* packet) {
    const auto index = static_cast<std::size_t>(packet->stream_index);
    if (required_[index] == 0) return;
    const auto start = packet_start_us(packet, source_->streams[index]);
    if (start == AV_NOPTS_VALUE) return;
    if (start < end_us_) consecutive_[index] = 0;
    else ++consecutive_[index];
  }

  bool done() const {
    bool active = false;
    for (std::size_t index = 0; index < required_.size(); ++index) {
      if (required_[index] == 0) continue;
      active = true;
      if (consecutive_[index] < required_[index]) return false;
    }
    return active;
  }

 private:
  const AVFormatContext* source_;
  std::int64_t end_us_;
  std::vector<std::size_t> consecutive_;
  std::vector<std::size_t> required_;
};

std::optional<MkvBoundaryAnalysis> analyze_constant_frame_boundaries(
    const std::string& input, std::size_t first_video_frame,
    std::size_t end_video_frame) {
  AVFormatContext* source = nullptr;
  AVPacket* packet = av_packet_alloc();
  auto cleanup = [&] { av_packet_free(&packet); avformat_close_input(&source); };
  if (!packet || !open_source(input, &source)) { cleanup(); return std::nullopt; }
  int video_stream = -1;
  for (unsigned i = 0; i < source->nb_streams; ++i) {
    if (source->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
        !is_attached_picture(source->streams[i])) { video_stream = static_cast<int>(i); break; }
  }
  if (video_stream < 0) { cleanup(); return std::nullopt; }
  const auto* stream = source->streams[video_stream];
  const auto codec_id = stream->codecpar->codec_id;
  if (codec_id == AV_CODEC_ID_MPEG1VIDEO || codec_id == AV_CODEC_ID_MPEG2VIDEO) {
    cleanup(); return std::nullopt;
  }
  AVRational frame_rate{}; std::int64_t first_pts = AV_NOPTS_VALUE;
  if (!constant_frame_timing(stream, frame_rate, first_pts)) { cleanup(); return std::nullopt; }
  MkvBoundaryAnalysis result;
  const auto record_tail_start = [&](std::size_t keyframe, std::size_t start) {
    const auto found = std::find_if(result.dependency_tail_encode_starts.begin(),
                                    result.dependency_tail_encode_starts.end(),
                                    [keyframe](const auto& point) { return point.first == keyframe; });
    if (found == result.dependency_tail_encode_starts.end())
      result.dependency_tail_encode_starts.emplace_back(keyframe, start);
    else
      found->second = std::min(found->second, start);
  };
  const auto scan_boundary = [&](std::size_t target_frame, bool find_next) {
    // MPEG-TS indexes frequently seek to the first packet after the requested
    // timestamp rather than the preceding access point. Start with bounded
    // preroll so both the next key after cut-in and previous key before cut-out
    // are observed without scanning the retained range.
    constexpr std::size_t seek_preroll_frames = 512;
    const auto seek_frame = target_frame > seek_preroll_frames
                                ? target_frame - seek_preroll_frames
                                : std::size_t{0};
    const auto target = frame_pts(seek_frame, stream, frame_rate, first_pts);
    if (av_seek_frame(source, video_stream, target, AVSEEK_FLAG_BACKWARD) < 0) return false;
    avformat_flush(source);
    bool saw_video = false;
    bool found_after_target = false;
    std::optional<std::size_t> current_random_access;
    std::size_t examined = 0;
    while (examined < 4096 && av_read_frame(source, packet) >= 0) {
      if (packet->stream_index == video_stream) {
        ++examined; saw_video = true;
        const auto mapped = frame_for_pts(packet_timestamp(packet), stream, frame_rate, first_pts);
        if (mapped) {
          const bool random_access = packet_has_random_access_nal(packet, stream->codecpar);
          if (random_access && *mapped >= first_video_frame && *mapped <= end_video_frame) {
            result.random_access_frames.push_back(*mapped);
            current_random_access = *mapped;
            record_tail_start(*mapped, *mapped);
          } else if (current_random_access && *mapped < *current_random_access) {
            record_tail_start(*current_random_access, *mapped);
          }
          if (*mapped > target_frame && (!find_next || random_access)) found_after_target = true;
          if (found_after_target || (!find_next && *mapped >= target_frame + 64)) {
            av_packet_unref(packet); break;
          }
        }
      }
      av_packet_unref(packet);
    }
    return saw_video;
  };
  // Only the first random-access point after the cut-in and the last one before
  // cut-out are needed to build the smart-render segments. Seeking each edge
  // avoids reading the entire retained range (which can be hundreds of GB).
  const bool saw_start = scan_boundary(first_video_frame, true);
  const bool saw_end = scan_boundary(end_video_frame, false);
  std::sort(result.random_access_frames.begin(), result.random_access_frames.end());
  result.random_access_frames.erase(
      std::unique(result.random_access_frames.begin(), result.random_access_frames.end()),
      result.random_access_frames.end());
  cleanup();
  if (!saw_start || !saw_end) return std::nullopt;
  return result;
}
}
#endif

MkvBoundaryAnalysis analyze_mkv_boundaries(const std::string& input,
                                           std::size_t first_video_frame,
                                           std::size_t end_video_frame) {
#ifndef SMARTCUT_HAS_FFMPEG
  (void)input; (void)first_video_frame; (void)end_video_frame; return {};
#else
  if (const auto fast = analyze_constant_frame_boundaries(input, first_video_frame,
                                                           end_video_frame)) return *fast;
  AVFormatContext* source = nullptr; AVCodecContext* decoder = nullptr; AVPacket* packet = av_packet_alloc(); AVFrame* frame = av_frame_alloc();
  MkvBoundaryAnalysis result; std::vector<std::int64_t> key_pts;
  auto cleanup = [&] { av_frame_free(&frame); av_packet_free(&packet); avcodec_free_context(&decoder); avformat_close_input(&source); };
  if (!packet || !frame || !open_source(input, &source)) { cleanup(); return result; }
  int video_stream = -1;
  for (unsigned i = 0; i < source->nb_streams; ++i) if (source->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && !is_attached_picture(source->streams[i])) { video_stream = static_cast<int>(i); break; }
  if (video_stream < 0) { cleanup(); return result; }
  const auto codec_id = source->streams[video_stream]->codecpar->codec_id;
  const bool mpeg2 = codec_id == AV_CODEC_ID_MPEG2VIDEO || codec_id == AV_CODEC_ID_MPEG1VIDEO;
  result.mpeg2_video = mpeg2;
  const bool strict_random_access = codec_id == AV_CODEC_ID_H264 || codec_id == AV_CODEC_ID_HEVC;
  const auto* codec = ffmpeg::preferred_video_decoder(codec_id); decoder = codec ? avcodec_alloc_context3(codec) : nullptr;
  if (!decoder || avcodec_parameters_to_context(decoder, source->streams[video_stream]->codecpar) < 0 || avcodec_open2(decoder, codec, nullptr) < 0) { cleanup(); return result; }
  std::size_t display_frame = 0; std::size_t preceding_b_frames = 0; bool done = false;
  auto receive = [&] {
    while (!done && avcodec_receive_frame(decoder, frame) >= 0) {
      const auto pts = frame->best_effort_timestamp != AV_NOPTS_VALUE ? frame->best_effort_timestamp : frame->pts;
      const bool key = std::find(key_pts.begin(), key_pts.end(), pts) != key_pts.end() ||
                       (!strict_random_access && (frame->flags & AV_FRAME_FLAG_KEY) != 0);
      if (key && display_frame >= first_video_frame && display_frame <= end_video_frame) {
        result.random_access_frames.push_back(display_frame);
        result.dependency_tail_encode_starts.emplace_back(
            display_frame, display_frame - std::min(display_frame, preceding_b_frames));
        if (mpeg2) result.mpeg2_tail_encode_starts.emplace_back(display_frame, display_frame - std::min(display_frame, preceding_b_frames));
      }
      // MPEG-2 B pictures use the following I/P picture as their forward reference. An
      // edit ending immediately after an I/P picture therefore contains every decode
      // dependency and can be packet-copied even though the endpoint itself is not a
      // random-access frame. Endpoints after a B picture remain conservatively encoded.
      if (mpeg2 && display_frame + 1 == end_video_frame) {
        result.mpeg2_end_dependency_complete = frame->pict_type == AV_PICTURE_TYPE_I ||
                                               frame->pict_type == AV_PICTURE_TYPE_P;
      }
      if (frame->pict_type == AV_PICTURE_TYPE_B) ++preceding_b_frames;
      else preceding_b_frames = 0;
      done = display_frame >= end_video_frame; ++display_frame; av_frame_unref(frame);
    }
  };
  while (!done && av_read_frame(source, packet) >= 0) {
    if (packet->stream_index == video_stream) {
      if (packet_has_random_access_nal(packet, source->streams[video_stream]->codecpar) && packet->pts != AV_NOPTS_VALUE) key_pts.push_back(packet->pts);
      if (avcodec_send_packet(decoder, packet) >= 0) receive();
    }
    av_packet_unref(packet);
  }
  if (!done) { avcodec_send_packet(decoder, nullptr); receive(); }
  cleanup(); return result;
#endif
}

std::vector<std::size_t> mkv_random_access_frames(const std::string& input,
                                                  std::size_t first_video_frame,
                                                  std::size_t end_video_frame) {
  return analyze_mkv_boundaries(input, first_video_frame, end_video_frame).random_access_frames;
}

std::string copy_mkv_timed_range(const std::string& input, const std::string& output,
                                 std::size_t first_video_packet, std::size_t end_video_packet) {
#ifndef SMARTCUT_HAS_FFMPEG
  (void)input; (void)output; (void)first_video_packet; (void)end_video_packet;
  return "{\"error\":\"FFmpeg support is not enabled\"}";
#else
  if (std::filesystem::weakly_canonical(input) == std::filesystem::weakly_canonical(output)) {
    return "{\"error\":\"source and output paths must differ\"}";
  }
  AVFormatContext* source = nullptr;
  AVFormatContext* destination = nullptr;
  AVPacket* packet = av_packet_alloc();
  bool completed = false;
  auto cleanup = [&] {
    av_packet_free(&packet);
    avformat_close_input(&source);
    if (destination && destination->pb) avio_closep(&destination->pb);
    avformat_free_context(destination);
    if (!completed) { std::error_code ignored; std::filesystem::remove(output, ignored); }
  };
  if (!packet || !open_source(input, &source)) {
    cleanup();
    return "{\"error\":\"range input open failed\"}";
  }
  TimedRange range;
  if (!determine_range(source, first_video_packet, end_video_packet, range)) {
    cleanup();
    return "{\"error\":\"range is invalid or does not begin with a key packet\"}";
  }
  if (!reopen(input, &source)) {
    cleanup();
    return "{\"error\":\"range input reopen failed\"}";
  }
  seek_to_range_start(source, range);

  std::int64_t timeline_base_us = std::numeric_limits<std::int64_t>::max();
  std::int64_t first_audio_us = std::numeric_limits<std::int64_t>::max();
  std::int64_t last_audio_end_us = std::numeric_limits<std::int64_t>::min();
  std::size_t video_index = 0;
  std::vector<std::int64_t> selection_timestamps(source->nb_streams, AV_NOPTS_VALUE);
  RangeEndTracker scan_end(source, range.end_us);
  while (av_read_frame(source, packet) >= 0) {
    bool split = false;
    if (selected_packet(packet, source, range, video_index, selection_timestamps, split) &&
        intermediate_stream_supported(source->streams[packet->stream_index])) {
      const auto* stream = source->streams[packet->stream_index];
      auto start = packet_start_us(packet, stream);
      if (start == AV_NOPTS_VALUE)
        start = selection_timestamps[static_cast<std::size_t>(packet->stream_index)];
      if (stream->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE && is_text_subtitle(stream->codecpar->codec_id)) {
        start = std::max(start, range.start_us);
      }
      timeline_base_us = std::min(timeline_base_us, start);
      if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
        const auto decode_start = packet_decode_us(packet, stream);
        if (decode_start != AV_NOPTS_VALUE) timeline_base_us = std::min(timeline_base_us, decode_start);
      }
      if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
        first_audio_us = std::min(first_audio_us, start);
        const auto raw_end = packet_end_us(packet, stream);
        last_audio_end_us = std::max(last_audio_end_us,
                                     raw_end == AV_NOPTS_VALUE ? start + 1 : raw_end);
      }
    }
    scan_end.observe(packet);
    av_packet_unref(packet);
    if (scan_end.done()) break;
  }
  if (timeline_base_us == std::numeric_limits<std::int64_t>::max() || !reopen(input, &source)) {
    cleanup();
    return "{\"error\":\"range contains no packets or cannot be reopened\"}";
  }
  seek_to_range_start(source, range);
  if (avformat_alloc_output_context2(&destination, nullptr, "matroska", output.c_str()) < 0 || !destination) {
    cleanup();
    return "{\"error\":\"range output context failed\"}";
  }
  av_dict_copy(&destination->metadata, source->metadata, 0);
  std::size_t audio_tracks = 0;
  std::size_t subtitle_tracks = 0;
  std::size_t attachments = 0;
  std::vector<int> stream_map(source->nb_streams, -1);
  for (unsigned i = 0; i < source->nb_streams; ++i) {
    if (!intermediate_stream_supported(source->streams[i])) continue;
    auto* output_stream = avformat_new_stream(destination, nullptr);
    if (!output_stream || avcodec_parameters_copy(output_stream->codecpar, source->streams[i]->codecpar) < 0) {
      cleanup();
      return "{\"error\":\"range stream copy failed\"}";
    }
    if (!normalize_pcm_parameters_for_matroska(output_stream->codecpar)) {
      cleanup();
      return "{\"error\":\"PCM stream cannot be represented losslessly in the Matroska working container\"}";
    }
    output_stream->codecpar->codec_tag = 0;
    supply_bitmap_subtitle_dimensions(output_stream->codecpar, source, range.video_stream);
    output_stream->time_base = source->streams[i]->time_base;
    copy_stream_attributes(output_stream, source->streams[i]);
    mark_pcm_bluray_origin(output_stream, source->streams[i]);
    mark_bitstream_audio_origin(output_stream, source->streams[i]);
    set_navigation_metadata(output_stream, source->streams[i], end_video_packet - first_video_packet);
    stream_map[i] = output_stream->index;
    audio_tracks += source->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO;
    subtitle_tracks += source->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE;
    attachments += source->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_ATTACHMENT;
  }
  std::size_t chapters = 0;
  for (unsigned i = 0; i < source->nb_chapters; ++i) {
    const auto* chapter = source->chapters[i];
    const auto chapter_start = av_rescale_q(chapter->start, chapter->time_base, AV_TIME_BASE_Q);
    const auto chapter_end = av_rescale_q(chapter->end, chapter->time_base, AV_TIME_BASE_Q);
    if (chapter_end <= range.start_us || chapter_start >= range.end_us) continue;
    auto* copied = static_cast<AVChapter*>(av_mallocz(sizeof(AVChapter)));
    auto** resized = static_cast<AVChapter**>(av_realloc_array(destination->chapters, destination->nb_chapters + 1, sizeof(AVChapter*)));
    if (!copied || !resized) { av_free(copied); cleanup(); return "{\"error\":\"range chapter allocation failed\"}"; }
    destination->chapters = resized;
    copied->id = chapter->id;
    copied->time_base = chapter->time_base;
    copied->start = av_rescale_q(std::max(chapter_start, range.start_us) - timeline_base_us, AV_TIME_BASE_Q, copied->time_base);
    copied->end = av_rescale_q(std::min(chapter_end, range.end_us) - timeline_base_us, AV_TIME_BASE_Q, copied->time_base);
    av_dict_copy(&copied->metadata, chapter->metadata, 0);
    destination->chapters[destination->nb_chapters++] = copied;
    ++chapters;
  }
  if ((!(destination->oformat->flags & AVFMT_NOFILE) && avio_open(&destination->pb, output.c_str(), AVIO_FLAG_WRITE) < 0) ||
      avformat_write_header(destination, nullptr) < 0) {
    cleanup();
    return "{\"error\":\"range output header failed\"}";
  }

  std::vector<std::size_t> packets_per_stream(source->nb_streams);
  std::vector<std::int64_t> last_output_dts(destination->nb_streams, AV_NOPTS_VALUE);
  std::size_t split_subtitles = 0;
  video_index = 0;
  selection_timestamps.assign(source->nb_streams, AV_NOPTS_VALUE);
  int result = 0;
  int failed_source_stream = -1;
  std::int64_t failed_pts = AV_NOPTS_VALUE;
  std::int64_t failed_dts = AV_NOPTS_VALUE;
  std::int64_t failed_offset = 0;
  RangeEndTracker write_end(source, range.end_us);
  while (result >= 0 && av_read_frame(source, packet) >= 0) {
    write_end.observe(packet);
    bool split = false;
    if (selected_packet(packet, source, range, video_index, selection_timestamps, split) && stream_map[static_cast<std::size_t>(packet->stream_index)] >= 0) {
      const auto source_index = packet->stream_index;
      const auto* input_stream = source->streams[source_index];
      auto* output_stream = destination->streams[static_cast<std::size_t>(stream_map[static_cast<std::size_t>(source_index)])];
      if (!normalize_pcm_packet_for_matroska(packet, input_stream->codecpar)) {
        result = AVERROR_INVALIDDATA;
        failed_source_stream = source_index;
        av_packet_unref(packet);
        break;
      }
      if (input_stream->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE && is_text_subtitle(input_stream->codecpar->codec_id)) {
        const auto raw_start = packet_start_us(packet, input_stream);
        const auto selected_start = raw_start == AV_NOPTS_VALUE ? selection_timestamps[static_cast<std::size_t>(source_index)] : raw_start;
        const auto raw_end = packet_end_us(packet, input_stream);
        const auto clipped_start = std::max(selected_start, range.start_us);
        const auto clipped_end = std::min(raw_end == AV_NOPTS_VALUE ? selected_start + 1 : raw_end, range.end_us);
        packet->pts = av_rescale_q(clipped_start, AV_TIME_BASE_Q, input_stream->time_base);
        packet->dts = packet->pts;
        packet->duration = std::max<std::int64_t>(1, av_rescale_q(clipped_end - clipped_start, AV_TIME_BASE_Q, input_stream->time_base));
        if (split) ++split_subtitles;
      }
      av_packet_rescale_ts(packet, input_stream->time_base, output_stream->time_base);
      const auto offset = av_rescale_q(timeline_base_us, AV_TIME_BASE_Q, output_stream->time_base);
      if (packet->pts != AV_NOPTS_VALUE) packet->pts -= offset;
      if (packet->dts != AV_NOPTS_VALUE) packet->dts -= offset;
      packet->stream_index = output_stream->index;
      packet->pos = -1;
      const auto output_index = static_cast<std::size_t>(output_stream->index);
      const auto step = std::max<std::int64_t>(packet->duration, 1);
      if (packet->pts == AV_NOPTS_VALUE && packet->dts == AV_NOPTS_VALUE) {
        packet->dts = last_output_dts[output_index] == AV_NOPTS_VALUE ? 0 : last_output_dts[output_index] + step;
        packet->pts = packet->dts;
      } else if (packet->dts == AV_NOPTS_VALUE) {
        packet->dts = last_output_dts[output_index] == AV_NOPTS_VALUE
                          ? std::max<std::int64_t>(packet->pts, 0)
                          : last_output_dts[output_index] + step;
      } else if (last_output_dts[output_index] != AV_NOPTS_VALUE &&
                 packet->dts <= last_output_dts[output_index]) {
        const auto corrected = last_output_dts[output_index] + step;
        if (packet->pts != AV_NOPTS_VALUE) packet->pts += corrected - packet->dts;
        packet->dts = corrected;
      }
      if (packet->pts == AV_NOPTS_VALUE) packet->pts = packet->dts;
      last_output_dts[output_index] = packet->dts;
      failed_source_stream = source_index;
      failed_pts = packet->pts;
      failed_dts = packet->dts;
      failed_offset = offset;
      result = av_interleaved_write_frame(destination, packet);
      if (result >= 0) ++packets_per_stream[static_cast<std::size_t>(source_index)];
    }
    av_packet_unref(packet);
    if (write_end.done()) break;
  }
  if (result >= 0) result = av_write_trailer(destination);
  if (result >= 0) completed = true;
  const auto duration_us = range.end_us - range.start_us;
  const auto output_duration_us = range.end_us - timeline_base_us;
  const auto leading_tolerance = first_audio_us == std::numeric_limits<std::int64_t>::max() ? 0 : range.start_us - first_audio_us;
  const auto trailing_tolerance = last_audio_end_us == std::numeric_limits<std::int64_t>::min() ? 0 : last_audio_end_us - range.end_us;
  std::size_t video_packets = packets_per_stream[static_cast<std::size_t>(range.video_stream)];
  std::size_t audio_packets = 0;
  std::size_t subtitle_events = 0;
  for (unsigned i = 0; i < source->nb_streams; ++i) {
    if (source->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) audio_packets += packets_per_stream[i];
    if (source->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) subtitle_events += packets_per_stream[i];
  }
  cleanup();
  if (result < 0) {
    char error_text[AV_ERROR_MAX_STRING_SIZE]{};
    av_strerror(result, error_text, sizeof(error_text));
    std::ostringstream report;
    report << "{\"error\":\"range packet mux failed\",\"ffmpeg_error\":\"" << error_text
           << "\",\"source_stream\":" << failed_source_stream << ",\"pts\":" << failed_pts
           << ",\"dts\":" << failed_dts << ",\"offset\":" << failed_offset << "}";
    return report.str();
  }
  std::ostringstream report;
  report << "{\"schema\":\"m11-timed-range-report-v1\",\"first_video_packet\":" << first_video_packet
         << ",\"end_video_packet\":" << end_video_packet << ",\"duration_us\":" << duration_us
         << ",\"output_duration_us\":" << output_duration_us
         << ",\"streams\":" << stream_map.size() - static_cast<std::size_t>(std::count(stream_map.begin(), stream_map.end(), -1)) << ",\"video_packets\":" << video_packets
         << ",\"audio_tracks\":" << audio_tracks << ",\"audio_packets\":" << audio_packets
         << ",\"subtitle_tracks\":" << subtitle_tracks << ",\"subtitle_events\":" << subtitle_events
         << ",\"split_text_subtitles\":" << split_subtitles << ",\"attachments\":" << attachments
         << ",\"chapters\":" << chapters << ",\"audio_leading_tolerance_us\":" << leading_tolerance
         << ",\"audio_trailing_tolerance_us\":" << trailing_tolerance
         << ",\"audio_policy\":\"complete-overlapping-codec-frames\",\"subtitle_policy\":\"split-text-copy-bitmap\"}";
  return report.str();
#endif
}

std::string validate_mkv_timed_range(const std::string& input, const std::string& output,
                                     std::size_t first_video_packet, std::size_t end_video_packet) {
#ifndef SMARTCUT_HAS_FFMPEG
  (void)input; (void)output; (void)first_video_packet; (void)end_video_packet;
  return "{\"schema\":\"m11-timed-range-validation-v1\",\"status\":\"FAILED VALIDATION\"}";
#else
  AVFormatContext* source = nullptr;
  AVFormatContext* rendered = nullptr;
  AVPacket* packet = av_packet_alloc();
  auto cleanup = [&] { av_packet_free(&packet); avformat_close_input(&source); avformat_close_input(&rendered); };
  if (!packet || !open_source(input, &source)) { cleanup(); return "{\"error\":\"validation source open failed\"}"; }
  TimedRange range;
  if (!determine_range(source, first_video_packet, end_video_packet, range) || !reopen(input, &source) || !open_source(output, &rendered)) {
    cleanup();
    return "{\"error\":\"validation range/output open failed\"}";
  }
  seek_to_range_start(source, range);
  std::vector<int> stream_map(source->nb_streams, -1);
  std::size_t supported_streams = 0;
  for (unsigned i = 0; i < source->nb_streams; ++i) if (intermediate_stream_supported(source->streams[i])) stream_map[i] = static_cast<int>(supported_streams++);
  bool metadata_match = supported_streams == rendered->nb_streams;
  for (unsigned i = 0; metadata_match && i < source->nb_streams; ++i) if (stream_map[i] >= 0) metadata_match = metadata_equal(source->streams[i], rendered->streams[static_cast<std::size_t>(stream_map[i])]);
  std::vector<std::vector<std::vector<std::uint8_t>>> expected(supported_streams);
  std::size_t video_index = 0;
  std::vector<std::int64_t> selection_timestamps(source->nb_streams, AV_NOPTS_VALUE);
  std::int64_t timeline_base_us = std::numeric_limits<std::int64_t>::max();
  RangeEndTracker expected_end(source, range.end_us);
  while (av_read_frame(source, packet) >= 0) {
    expected_end.observe(packet);
    bool split = false;
    const auto mapped = stream_map[static_cast<std::size_t>(packet->stream_index)];
    if (selected_packet(packet, source, range, video_index, selection_timestamps, split) && mapped >= 0) {
      expected[static_cast<std::size_t>(mapped)].push_back(
          matroska_normalized_payload(packet, source->streams[packet->stream_index]->codecpar));
      const auto* stream = source->streams[packet->stream_index];
      auto start = packet_start_us(packet, stream);
      if (start == AV_NOPTS_VALUE)
        start = selection_timestamps[static_cast<std::size_t>(packet->stream_index)];
      if (stream->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE && is_text_subtitle(stream->codecpar->codec_id)) start = std::max(start, range.start_us);
      timeline_base_us = std::min(timeline_base_us, start);
      if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
        {
          const auto decode_start = packet_decode_us(packet, stream);
          if (decode_start != AV_NOPTS_VALUE) timeline_base_us = std::min(timeline_base_us, decode_start);
        }
    }
    av_packet_unref(packet);
    if (expected_end.done()) break;
  }
  std::vector<std::vector<std::vector<std::uint8_t>>> actual(rendered->nb_streams);
  std::vector<std::int64_t> last_dts(rendered->nb_streams, AV_NOPTS_VALUE);
  std::vector<bool> seen_nonnegative_dts(rendered->nb_streams, false);
  std::size_t timing_violations = 0;
  std::size_t subtitle_bounds_violations = 0;
  const auto duration_us = range.end_us - timeline_base_us;
  while (av_read_frame(rendered, packet) >= 0) {
    const auto stream_index = static_cast<std::size_t>(packet->stream_index);
    actual[stream_index].emplace_back(packet->data, packet->data + packet->size);
    const bool dts_regressed = packet->dts != AV_NOPTS_VALUE && last_dts[stream_index] != AV_NOPTS_VALUE &&
                               packet->dts < last_dts[stream_index];
    const bool leading_video_decode_preroll = packet->dts != AV_NOPTS_VALUE && packet->dts < 0 &&
        !seen_nonnegative_dts[stream_index] &&
        rendered->streams[stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO;
    const bool reconstructed_mpeg2_dts =
        rendered->streams[stream_index]->codecpar->codec_id == AV_CODEC_ID_MPEG2VIDEO;
    if (packet->pts == AV_NOPTS_VALUE || packet->pts < 0 ||
        (packet->dts != AV_NOPTS_VALUE && packet->dts < 0 && !leading_video_decode_preroll) ||
        (dts_regressed && !reconstructed_mpeg2_dts)) ++timing_violations;
    if (packet->dts != AV_NOPTS_VALUE) {
      if (packet->dts >= 0) seen_nonnegative_dts[stream_index] = true;
      last_dts[stream_index] = packet->dts;
    }
    const auto* stream = rendered->streams[stream_index];
    if (stream->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
      const auto start = packet_start_us(packet, stream);
      const auto finish = packet_end_us(packet, stream);
      if (start < 0 || finish > duration_us) ++subtitle_bounds_violations;
    }
    av_packet_unref(packet);
  }
  std::size_t payload_mismatches = expected.size() == actual.size() ? 0 : 1;
  for (std::size_t stream = 0; stream < std::min(expected.size(), actual.size()); ++stream)
    if (!packet_payloads_equal(expected[stream], actual[stream],
                               rendered->streams[stream]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO))
      ++payload_mismatches;
  std::size_t expected_chapters = 0;
  for (unsigned i = 0; i < source->nb_chapters; ++i) {
    const auto* chapter = source->chapters[i];
    const auto chapter_start = av_rescale_q(chapter->start, chapter->time_base, AV_TIME_BASE_Q);
    const auto chapter_end = av_rescale_q(chapter->end, chapter->time_base, AV_TIME_BASE_Q);
    if (chapter_end > range.start_us && chapter_start < range.end_us) ++expected_chapters;
  }
  bool chapter_valid = rendered->nb_chapters == expected_chapters;
  for (unsigned i = 0; chapter_valid && i < rendered->nb_chapters; ++i) {
    const auto* chapter = rendered->chapters[i];
    const auto start = av_rescale_q(chapter->start, chapter->time_base, AV_TIME_BASE_Q);
    const auto end = av_rescale_q(chapter->end, chapter->time_base, AV_TIME_BASE_Q);
    chapter_valid = start >= 0 && end >= start && end <= duration_us;
  }
  const bool passed = metadata_match && payload_mismatches == 0 && timing_violations == 0 &&
                      subtitle_bounds_violations == 0 && chapter_valid;
  const auto streams = rendered->nb_streams;
  cleanup();
  std::ostringstream report;
  report << "{\"schema\":\"m11-timed-range-validation-v1\",\"status\":\"" << (passed ? "PASSED" : "FAILED VALIDATION")
         << "\",\"streams\":" << streams << ",\"metadata_match\":" << (metadata_match ? "true" : "false")
         << ",\"payload_mismatches\":" << payload_mismatches << ",\"timing_violations\":" << timing_violations
         << ",\"subtitle_bounds_violations\":" << subtitle_bounds_violations
         << ",\"chapter_valid\":" << (chapter_valid ? "true" : "false") << "}";
  return report.str();
#endif
}

std::string mux_mkv_boundary_timed_range(const std::string& input, const std::string& boundary_video,
                                         const std::string& output, std::size_t first_video_frame,
                                         std::size_t end_video_frame) {
#ifndef SMARTCUT_HAS_FFMPEG
  (void)input; (void)boundary_video; (void)output; (void)first_video_frame; (void)end_video_frame;
  return "{\"error\":\"FFmpeg support is not enabled\"}";
#else
  if (std::filesystem::weakly_canonical(input) == std::filesystem::weakly_canonical(output) ||
      std::filesystem::weakly_canonical(boundary_video) == std::filesystem::weakly_canonical(output))
    return "{\"error\":\"source, boundary, and output paths must differ\"}";
  AVFormatContext* source = nullptr; AVFormatContext* boundary = nullptr; AVFormatContext* destination = nullptr;
  AVPacket* packet = av_packet_alloc(); AVPacket* boundary_packet = av_packet_alloc(); bool completed = false;
  auto cleanup = [&] {
    av_packet_free(&packet); av_packet_free(&boundary_packet); avformat_close_input(&source); avformat_close_input(&boundary);
    if (destination && destination->pb) avio_closep(&destination->pb);
    avformat_free_context(destination);
    if (!completed) { std::error_code ignored; std::filesystem::remove(output, ignored); }
  };
  if (!packet || !boundary_packet || !open_source(input, &source)) { cleanup(); return "{\"error\":\"boundary mux source open failed\"}"; }
  TimedRange range;
  if (!determine_range(source, first_video_frame, end_video_frame, range, false) || !reopen(input, &source) ||
      !open_source(boundary_video, &boundary)) { cleanup(); return "{\"error\":\"boundary mux range or input invalid\"}"; }
  seek_to_range_start(source, range);
  int boundary_stream = -1; unsigned source_video_count = 0;
  for (unsigned i = 0; i < source->nb_streams; ++i) source_video_count += source->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && !is_attached_picture(source->streams[i]);
  for (unsigned i = 0; i < boundary->nb_streams; ++i) if (boundary->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { boundary_stream = static_cast<int>(i); break; }
  if (source_video_count != 1 || boundary_stream < 0) { cleanup(); return "{\"error\":\"boundary mux requires one source video stream\"}"; }

  std::int64_t boundary_first_pts_us = AV_NOPTS_VALUE;
  while (av_read_frame(boundary, packet) >= 0) {
    if (packet->stream_index == boundary_stream) {
      if (boundary_first_pts_us == AV_NOPTS_VALUE && packet->pts != AV_NOPTS_VALUE)
        boundary_first_pts_us = av_rescale_q(packet->pts, boundary->streams[boundary_stream]->time_base,
                                             AV_TIME_BASE_Q);
    }
    av_packet_unref(packet);
  }
  if (!reopen(boundary_video, &boundary)) { cleanup(); return "{\"error\":\"boundary mux reopen failed\"}"; }

  std::int64_t timeline_base_us = range.start_us;
  std::size_t video_index = 0;
  std::vector<std::int64_t> selection_timestamps(source->nb_streams, AV_NOPTS_VALUE);
  RangeEndTracker scan_end(source, range.end_us);
  while (av_read_frame(source, packet) >= 0) {
    scan_end.observe(packet);
    bool split = false;
    if (intermediate_stream_supported(source->streams[packet->stream_index]) && !is_attached_picture(source->streams[packet->stream_index]) && selected_packet(packet, source, range, video_index, selection_timestamps, split) && packet->stream_index != range.video_stream &&
        source->streams[packet->stream_index]->codecpar->codec_type != AVMEDIA_TYPE_ATTACHMENT) {
      const auto* stream = source->streams[packet->stream_index];
      const auto start = packet_start_us(packet, stream);
      // Subtitle display intervals commonly begin several seconds before a cut and
      // overlap it.  They are clipped below; they must not move the whole output
      // timeline backwards and create leading black video.
      if (stream->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE && start != AV_NOPTS_VALUE)
        timeline_base_us = std::min(timeline_base_us, start);
    }
    av_packet_unref(packet);
    if (scan_end.done()) break;
  }
  if (!reopen(input, &source) || avformat_alloc_output_context2(&destination, nullptr, "matroska", output.c_str()) < 0 || !destination) {
    cleanup(); return "{\"error\":\"boundary mux output setup failed\"}" ;
  }
  // MPEG video normally begins with a negative decode timestamp because the
  // first displayed picture is decoded ahead of its B-picture reorder window.
  // Matroska and DirectShow both support that preroll.  Do not let libavformat
  // shift the whole presentation timeline forward to eliminate it.
  destination->avoid_negative_ts = AVFMT_AVOID_NEG_TS_DISABLED;
  seek_to_range_start(source, range);
  av_dict_copy(&destination->metadata, source->metadata, 0);
  std::vector<int> stream_map(source->nb_streams, -1);
  std::size_t skipped_unsupported_streams = 0;
  for (unsigned i = 0; i < source->nb_streams; ++i) {
    if (!intermediate_stream_supported(source->streams[i])) { ++skipped_unsupported_streams; continue; }
    auto* out = avformat_new_stream(destination, nullptr);
    const auto* parameters = static_cast<int>(i) == range.video_stream ? boundary->streams[boundary_stream]->codecpar : source->streams[i]->codecpar;
    if (!out || avcodec_parameters_copy(out->codecpar, parameters) < 0) { cleanup(); return "{\"error\":\"boundary mux stream setup failed\"}"; }
    if (!normalize_pcm_parameters_for_matroska(out->codecpar)) {
      cleanup();
      return "{\"error\":\"PCM stream cannot be represented losslessly in the Matroska working container\"}";
    }
    out->codecpar->codec_tag = 0;
    supply_bitmap_subtitle_dimensions(out->codecpar, source, range.video_stream);
    out->time_base = static_cast<int>(i) == range.video_stream ? boundary->streams[boundary_stream]->time_base : source->streams[i]->time_base;
    copy_stream_attributes(out, source->streams[i]);
    mark_pcm_bluray_origin(out, source->streams[i]);
    mark_bitstream_audio_origin(out, source->streams[i]);
    set_navigation_metadata(out, source->streams[i], end_video_frame - first_video_frame);
    stream_map[i] = out->index;
  }
  std::size_t chapters = 0;
  for (unsigned i = 0; i < source->nb_chapters; ++i) {
    const auto* chapter = source->chapters[i];
    const auto chapter_start = av_rescale_q(chapter->start, chapter->time_base, AV_TIME_BASE_Q);
    const auto chapter_end = av_rescale_q(chapter->end, chapter->time_base, AV_TIME_BASE_Q);
    if (chapter_end <= range.start_us || chapter_start >= range.end_us) continue;
    auto* copied = static_cast<AVChapter*>(av_mallocz(sizeof(AVChapter)));
    auto** resized = static_cast<AVChapter**>(av_realloc_array(destination->chapters, destination->nb_chapters + 1, sizeof(AVChapter*)));
    if (!copied || !resized) { av_free(copied); cleanup(); return "{\"error\":\"boundary mux chapter allocation failed\"}"; }
    destination->chapters = resized; copied->id = chapter->id; copied->time_base = chapter->time_base;
    copied->start = av_rescale_q(std::max(chapter_start, range.start_us) - timeline_base_us, AV_TIME_BASE_Q, copied->time_base);
    copied->end = av_rescale_q(std::min(chapter_end, range.end_us) - timeline_base_us, AV_TIME_BASE_Q, copied->time_base);
    av_dict_copy(&copied->metadata, chapter->metadata, 0); destination->chapters[destination->nb_chapters++] = copied; ++chapters;
  }
  if ((!(destination->oformat->flags & AVFMT_NOFILE) && avio_open(&destination->pb, output.c_str(), AVIO_FLAG_WRITE) < 0) ||
      avformat_write_header(destination, nullptr) < 0) { cleanup(); return "{\"error\":\"boundary mux header failed\"}"; }
  int result = 0; std::size_t video_packets = 0; std::size_t source_packets = 0;
  int failed_stream = -1; std::int64_t failed_pts = AV_NOPTS_VALUE; std::int64_t failed_dts = AV_NOPTS_VALUE;
  bool failed_video_packet = false;
  auto* output_video = destination->streams[static_cast<std::size_t>(stream_map[static_cast<std::size_t>(range.video_stream)])];
  const auto boundary_offset = av_rescale_q(
      boundary_first_pts_us == AV_NOPTS_VALUE ? 0 : -boundary_first_pts_us,
      AV_TIME_BASE_Q, output_video->time_base);
  video_index = 0;
  selection_timestamps.assign(source->nb_streams, AV_NOPTS_VALUE);
  RangeEndTracker write_end(source, range.end_us);
  bool boundary_ready = false; bool boundary_done = false;
  bool source_ready = false; bool source_done = false;
  const auto load_boundary_packet = [&] {
    if (boundary_ready || boundary_done || result < 0) return boundary_ready;
    while (av_read_frame(boundary, boundary_packet) >= 0) {
      if (boundary_packet->stream_index != boundary_stream) { av_packet_unref(boundary_packet); continue; }
      av_packet_rescale_ts(boundary_packet, boundary->streams[boundary_stream]->time_base, output_video->time_base);
      if (boundary_packet->pts != AV_NOPTS_VALUE) boundary_packet->pts += boundary_offset;
      if (boundary_packet->dts != AV_NOPTS_VALUE) boundary_packet->dts += boundary_offset;
      if (boundary_packet->pts == AV_NOPTS_VALUE) boundary_packet->pts = boundary_packet->dts;
      boundary_packet->stream_index = output_video->index; boundary_packet->pos = -1;
      boundary_ready = true; return true;
    }
    boundary_done = true; return false;
  };
  const auto load_source_packet = [&] {
    if (source_ready || source_done || result < 0) return source_ready;
    while (av_read_frame(source, packet) >= 0) {
      write_end.observe(packet);
      bool split = false;
      const auto source_index = packet->stream_index;
      const bool attached_picture = is_attached_picture(source->streams[source_index]);
      const bool selected = stream_map[static_cast<std::size_t>(source_index)] >= 0 &&
          (attached_picture || selected_packet(packet, source, range, video_index, selection_timestamps, split)) &&
          source_index != range.video_stream && source->streams[source_index]->codecpar->codec_type != AVMEDIA_TYPE_ATTACHMENT;
      if (selected) {
        const auto* in = source->streams[source_index];
        auto* out = destination->streams[static_cast<std::size_t>(stream_map[static_cast<std::size_t>(source_index)])];
        if (!normalize_pcm_packet_for_matroska(packet, in->codecpar)) {
          result = AVERROR_INVALIDDATA; source_done = true; av_packet_unref(packet); return false;
        }
        if (attached_picture) { packet->pts = 0; packet->dts = 0; packet->duration = 0; }
        else if (in->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
          const auto raw_start = packet_start_us(packet, in);
          const auto selected_start = raw_start == AV_NOPTS_VALUE ? selection_timestamps[static_cast<std::size_t>(source_index)] : raw_start;
          const auto raw_end = packet_end_us(packet, in);
          const auto clipped_start = std::max(selected_start, range.start_us);
          const auto clipped_end = std::min(raw_end == AV_NOPTS_VALUE ? selected_start + 1 : raw_end, range.end_us);
          packet->pts = av_rescale_q(clipped_start, AV_TIME_BASE_Q, in->time_base); packet->dts = packet->pts;
          packet->duration = std::max<std::int64_t>(1, av_rescale_q(clipped_end - clipped_start, AV_TIME_BASE_Q, in->time_base));
        }
        av_packet_rescale_ts(packet, in->time_base, out->time_base);
        const auto offset = av_rescale_q(timeline_base_us, AV_TIME_BASE_Q, out->time_base);
        if (packet->pts != AV_NOPTS_VALUE) packet->pts -= offset;
        if (packet->dts != AV_NOPTS_VALUE) packet->dts -= offset;
        packet->stream_index = out->index; packet->pos = -1;
        source_ready = true; return true;
      }
      av_packet_unref(packet);
      if (write_end.done()) break;
    }
    source_done = true; return false;
  };
  const auto packet_order_us = [&](const AVPacket* item) {
    const auto timestamp = item->dts != AV_NOPTS_VALUE ? item->dts : item->pts;
    return timestamp == AV_NOPTS_VALUE ? std::numeric_limits<std::int64_t>::max() :
        av_rescale_q(timestamp, destination->streams[item->stream_index]->time_base, AV_TIME_BASE_Q);
  };
  while (result == 0) {
    load_boundary_packet(); load_source_packet();
    if (!boundary_ready && !source_ready) break;
    const bool write_video = boundary_ready && (!source_ready || packet_order_us(boundary_packet) <= packet_order_us(packet));
    auto* selected = write_video ? boundary_packet : packet;
    const auto selected_stream = selected->stream_index;
    const auto selected_pts = selected->pts;
    const auto selected_dts = selected->dts;
    // Matroska stores presentation timestamps but not decode timestamps. The
    // intermediate segment's demuxed DTS can therefore be missing or repeated
    // around B-frame reordering. We already merge packets in physical decode
    // order above; let the Matroska muxer derive video decode timing while
    // retaining source DTS for copied audio and subtitle streams.
    const bool derived_video_dts = output_video->codecpar->codec_id == AV_CODEC_ID_HEVC ||
                                   output_video->codecpar->codec_id == AV_CODEC_ID_MPEG2VIDEO;
    if (write_video && derived_video_dts) selected->dts = AV_NOPTS_VALUE;
    const auto write_result = derived_video_dts ? av_write_frame(destination, selected)
                                                : av_interleaved_write_frame(destination, selected);
    av_packet_unref(selected);
    if (write_result < 0) {
      result = write_result; failed_stream = selected_stream; failed_pts = selected_pts;
      failed_dts = selected_dts; failed_video_packet = write_video;
    }
    else if (write_video) { ++video_packets; boundary_ready = false; }
    else { ++source_packets; source_ready = false; }
  }
  if (result == 0) result = av_write_trailer(destination);
  if (result == 0) completed = true;
  cleanup();
  if (result < 0) { char error_text[AV_ERROR_MAX_STRING_SIZE]{}; av_strerror(result, error_text, sizeof(error_text)); std::ostringstream report; report << "{\"error\":\"boundary mux packet write failed: " << error_text << "\",\"stream\":" << failed_stream << ",\"packet_kind\":\"" << (failed_video_packet ? "boundary-video" : "source") << "\",\"pts\":" << failed_pts << ",\"dts\":" << failed_dts << "}"; return report.str(); }
  std::ostringstream report;
  report << "{\"schema\":\"boundary-timed-mux-report-v1\",\"video_packets\":" << video_packets
         << ",\"source_packets\":" << source_packets << ",\"chapters\":" << chapters
         << ",\"skipped_unsupported_streams\":" << skipped_unsupported_streams
         << ",\"timeline_base_us\":" << timeline_base_us
         << ",\"boundary_timestamp_shift_us\":"
         << (boundary_first_pts_us == AV_NOPTS_VALUE ? 0 : -boundary_first_pts_us) << "}";
  return report.str();
#endif
}

std::string validate_mkv_boundary_timed_range(const std::string& input, const std::string& boundary_video,
                                              const std::string& output, std::size_t first_video_frame,
                                              std::size_t end_video_frame) {
#ifndef SMARTCUT_HAS_FFMPEG
  (void)input; (void)boundary_video; (void)output; (void)first_video_frame; (void)end_video_frame;
  return "{\"schema\":\"boundary-timed-validation-v1\",\"status\":\"FAILED VALIDATION\"}";
#else
  AVFormatContext* source = nullptr; AVFormatContext* boundary = nullptr; AVFormatContext* rendered = nullptr; AVPacket* packet = av_packet_alloc();
  auto cleanup = [&] { av_packet_free(&packet); avformat_close_input(&source); avformat_close_input(&boundary); avformat_close_input(&rendered); };
  if (!packet || !open_source(input, &source)) { cleanup(); return "{\"error\":\"boundary validation source open failed\"}"; }
  TimedRange range;
  if (!determine_range(source, first_video_frame, end_video_frame, range, false) || !reopen(input, &source) ||
      !open_source(boundary_video, &boundary) || !open_source(output, &rendered)) {
    cleanup(); return "{\"error\":\"boundary validation input open failed\"}";
  }
  seek_to_range_start(source, range);
  int boundary_stream = -1;
  for (unsigned i = 0; i < boundary->nb_streams; ++i) if (boundary->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { boundary_stream = static_cast<int>(i); break; }
  std::vector<int> stream_map(source->nb_streams, -1);
  std::size_t supported_streams = 0;
  for (unsigned i = 0; i < source->nb_streams; ++i) if (intermediate_stream_supported(source->streams[i])) stream_map[i] = static_cast<int>(supported_streams++);
  bool metadata_match = boundary_stream >= 0 && supported_streams == rendered->nb_streams;
  for (unsigned i = 0; metadata_match && i < source->nb_streams; ++i) {
    if (stream_map[i] < 0) continue;
    const auto rendered_index = static_cast<std::size_t>(stream_map[i]);
    if (static_cast<int>(i) != range.video_stream) {
      if (is_attached_picture(source->streams[i])) metadata_match = source->streams[i]->codecpar->codec_type == rendered->streams[rendered_index]->codecpar->codec_type && source->streams[i]->codecpar->codec_id == rendered->streams[rendered_index]->codecpar->codec_id;
      else metadata_match = metadata_equal(source->streams[i], rendered->streams[rendered_index]);
      continue;
    }
    const auto* expected_codec = boundary->streams[boundary_stream]->codecpar; const auto* actual_codec = rendered->streams[rendered_index]->codecpar;
    metadata_match = expected_codec->codec_type == actual_codec->codec_type && expected_codec->codec_id == actual_codec->codec_id &&
                     source->streams[i]->codecpar->codec_type == rendered->streams[rendered_index]->codecpar->codec_type;
  }
  struct PayloadAudit {
    std::size_t packets{};
    std::size_t bytes{};
    std::uint64_t hash{14695981039346656037ULL};
    void add(const AVPacket* item, const AVCodecParameters* source_parameters = nullptr) {
      const auto payload = matroska_normalized_payload(item, source_parameters);
      ++packets; bytes += payload.size();
      for (const auto byte : payload) { hash ^= byte; hash *= 1099511628211ULL; }
    }
  };
  const bool complete_payload_audit = end_video_frame - first_video_frame <= 512;
  std::vector<std::vector<std::vector<std::uint8_t>>> expected(complete_payload_audit ? supported_streams : 0),
      actual(complete_payload_audit ? rendered->nb_streams : 0);
  std::vector<PayloadAudit> expected_audit(supported_streams), actual_audit(rendered->nb_streams);
  while (boundary_stream >= 0 && av_read_frame(boundary, packet) >= 0) {
    if (packet->stream_index == boundary_stream) {
      const auto mapped = static_cast<std::size_t>(stream_map[static_cast<std::size_t>(range.video_stream)]);
      expected_audit[mapped].add(packet);
      if (complete_payload_audit) expected[mapped].emplace_back(packet->data, packet->data + packet->size);
    }
    av_packet_unref(packet);
  }
  std::size_t video_index = 0;
  std::vector<std::int64_t> selection_timestamps(source->nb_streams, AV_NOPTS_VALUE);
  RangeEndTracker expected_end(source, range.end_us);
  while (av_read_frame(source, packet) >= 0) {
    expected_end.observe(packet);
    bool split = false; const auto index = packet->stream_index;
    if (stream_map[static_cast<std::size_t>(index)] >= 0 && (is_attached_picture(source->streams[index]) || selected_packet(packet, source, range, video_index, selection_timestamps, split)) && index != range.video_stream &&
        source->streams[index]->codecpar->codec_type != AVMEDIA_TYPE_ATTACHMENT)
      {
        const auto mapped = static_cast<std::size_t>(stream_map[static_cast<std::size_t>(index)]);
        expected_audit[mapped].add(packet, source->streams[index]->codecpar);
        if (complete_payload_audit)
          expected[mapped].push_back(matroska_normalized_payload(packet, source->streams[index]->codecpar));
      }
    av_packet_unref(packet);
    if (expected_end.done()) break;
  }
  std::vector<std::int64_t> last_dts(rendered->nb_streams, AV_NOPTS_VALUE);
  std::vector<bool> seen_nonnegative_dts(rendered->nb_streams, false);
  std::vector<std::size_t> timing_violations_by_stream(rendered->nb_streams, 0);
  std::size_t negative_pts = 0;
  std::size_t negative_dts = 0;
  std::size_t leading_video_decode_preroll_packets = 0;
  std::size_t dts_regressions = 0;
  std::int64_t first_video_pts = AV_NOPTS_VALUE;
  std::int64_t first_video_dts = AV_NOPTS_VALUE;
  std::size_t audio_streams = 0;
  for (unsigned index = 0; index < rendered->nb_streams; ++index)
    audio_streams += rendered->streams[index]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO;
  std::size_t physical_packet_position = 0;
  std::size_t first_audio_packet_position = std::numeric_limits<std::size_t>::max();
  std::size_t timing_violations = 0;
  while (av_read_frame(rendered, packet) >= 0) {
    const auto index = static_cast<std::size_t>(packet->stream_index);
    if (rendered->streams[index]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
        first_audio_packet_position == std::numeric_limits<std::size_t>::max())
      first_audio_packet_position = physical_packet_position;
    ++physical_packet_position;
    actual_audit[index].add(packet);
    if (complete_payload_audit) actual[index].emplace_back(packet->data, packet->data + packet->size);
    const bool pts_negative = packet->pts != AV_NOPTS_VALUE && packet->pts < 0;
    const bool dts_negative = packet->dts != AV_NOPTS_VALUE && packet->dts < 0;
    const bool dts_regressed = packet->dts != AV_NOPTS_VALUE && last_dts[index] != AV_NOPTS_VALUE && packet->dts < last_dts[index];
    const bool video = rendered->streams[index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO;
    if (video && first_video_pts == AV_NOPTS_VALUE) {
      first_video_pts = packet->pts;
      first_video_dts = packet->dts;
    }
    const bool leading_video_decode_preroll = dts_negative && video && !seen_nonnegative_dts[index];
    if (leading_video_decode_preroll) ++leading_video_decode_preroll_packets;
    if (dts_regressed) ++dts_regressions;
    const bool reconstructed_mpeg2_dts =
        video && rendered->streams[index]->codecpar->codec_id == AV_CODEC_ID_MPEG2VIDEO;
    if (pts_negative || (dts_negative && !leading_video_decode_preroll) ||
        (dts_regressed && !reconstructed_mpeg2_dts)) {
      if (pts_negative) ++negative_pts;
      if (dts_negative && !leading_video_decode_preroll) ++negative_dts;
      ++timing_violations;
      ++timing_violations_by_stream[index];
    }
    if (packet->dts != AV_NOPTS_VALUE) {
      if (packet->dts >= 0) seen_nonnegative_dts[index] = true;
      last_dts[index] = packet->dts;
    }
    av_packet_unref(packet);
  }
  std::size_t payload_mismatches = expected_audit.size() == actual_audit.size() ? 0 : 1;
  std::vector<std::size_t> payload_mismatch_streams;
  std::vector<std::size_t> expected_packets(expected_audit.size()), actual_packets(actual_audit.size());
  std::vector<std::size_t> expected_bytes(expected_audit.size()), actual_bytes(actual_audit.size());
  for (std::size_t stream = 0; stream < expected_audit.size(); ++stream) {
    expected_packets[stream] = expected_audit[stream].packets; expected_bytes[stream] = expected_audit[stream].bytes;
  }
  for (std::size_t stream = 0; stream < actual_audit.size(); ++stream) {
    actual_packets[stream] = actual_audit[stream].packets; actual_bytes[stream] = actual_audit[stream].bytes;
  }
  for (std::size_t stream = 0; stream < std::min(expected_audit.size(), actual_audit.size()); ++stream) {
    const bool payload_equal = complete_payload_audit ?
        packet_payloads_equal(expected[stream], actual[stream],
                              rendered->streams[stream]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO,
                              rendered->streams[stream]->codecpar->codec_id == AV_CODEC_ID_TRUEHD) :
        expected_audit[stream].packets == actual_audit[stream].packets &&
        expected_audit[stream].bytes == actual_audit[stream].bytes &&
        expected_audit[stream].hash == actual_audit[stream].hash;
    if (!payload_equal) {
      ++payload_mismatches;
      payload_mismatch_streams.push_back(stream);
    }
  }
  std::size_t expected_chapters = 0;
  for (unsigned i = 0; i < source->nb_chapters; ++i) {
    const auto start = av_rescale_q(source->chapters[i]->start, source->chapters[i]->time_base, AV_TIME_BASE_Q);
    const auto end = av_rescale_q(source->chapters[i]->end, source->chapters[i]->time_base, AV_TIME_BASE_Q);
    expected_chapters += end > range.start_us && start < range.end_us;
  }
  const bool chapter_valid = rendered->nb_chapters == expected_chapters;
  const bool interleave_valid = audio_streams == 0 || first_audio_packet_position <= 16;
  const bool passed = metadata_match && payload_mismatches == 0 && timing_violations == 0 &&
                      chapter_valid && interleave_valid;
  const auto streams = rendered->nb_streams; cleanup(); std::ostringstream report;
  report << "{\"schema\":\"boundary-timed-validation-v1\",\"status\":\"" << (passed ? "PASSED" : "FAILED VALIDATION")
         << "\",\"streams\":" << streams << ",\"metadata_match\":" << (metadata_match ? "true" : "false")
         << ",\"payload_audit\":\"" << (complete_payload_audit ? "complete" : "streaming-hash") << "\""
         << ",\"payload_mismatches\":" << payload_mismatches << ",\"timing_violations\":" << timing_violations
         << ",\"negative_pts\":" << negative_pts << ",\"negative_dts\":" << negative_dts
         << ",\"leading_video_decode_preroll_packets\":" << leading_video_decode_preroll_packets
         << ",\"dts_regressions\":" << dts_regressions
         << ",\"first_video_pts\":" << first_video_pts << ",\"first_video_dts\":" << first_video_dts
         << ",\"first_audio_packet_position\":"
         << (first_audio_packet_position == std::numeric_limits<std::size_t>::max() ? -1 :
             static_cast<std::int64_t>(first_audio_packet_position))
         << ",\"interleave_valid\":" << (interleave_valid ? "true" : "false")
         << ",\"timing_violations_by_stream\":[";
  for (std::size_t index = 0; index < timing_violations_by_stream.size(); ++index) {
    if (index) report << ',';
    report << timing_violations_by_stream[index];
  }
  report << ']'
         << ",\"payload_mismatch_streams\":[";
  for (std::size_t index = 0; index < payload_mismatch_streams.size(); ++index) {
    if (index) report << ',';
    report << payload_mismatch_streams[index];
  }
  report << ']' << ",\"expected_packets_by_stream\":[";
  for (std::size_t index = 0; index < expected_packets.size(); ++index) { if (index) report << ','; report << expected_packets[index]; }
  report << ']' << ",\"actual_packets_by_stream\":[";
  for (std::size_t index = 0; index < actual_packets.size(); ++index) { if (index) report << ','; report << actual_packets[index]; }
  report << ']' << ",\"expected_bytes_by_stream\":[";
  for (std::size_t index = 0; index < expected_bytes.size(); ++index) { if (index) report << ','; report << expected_bytes[index]; }
  report << ']' << ",\"actual_bytes_by_stream\":[";
  for (std::size_t index = 0; index < actual_bytes.size(); ++index) { if (index) report << ','; report << actual_bytes[index]; }
  report << ']'
         << ",\"chapter_valid\":" << (chapter_valid ? "true" : "false") << "}";
  return report.str();
#endif
}
}
