/* SPDX-License-Identifier: BSD-2-Clause */ /* * parser.c — Phase 8.3 parse-path tool. * * Opens a media file via FFmpeg's avformat demuxer (dlopen'd * by ffmpeg_loader), finds the first video stream, and logs * per-frame metadata (size, pts, dts, flags) without decoding. * * Run: * daedalus_v4l2_daemon parse /path/to/sample.ivf * * For Phase 8.3 acceptance: parses any container FFmpeg * supports; logs frame counts + per-codec confirmation. * Block-level metadata extraction (the actual per-block QPU * dispatch info) is Phase 8.4 work. */ #include "parser.h" #include "ffmpeg_loader.h" #include "log.h" #include #include #include #include #include #include /* AVERROR_EOF without dragging the macro from FFmpeg's averror.h. */ #ifndef AVERROR_EOF #define AVERROR_EOF (-('E' | ('O' << 8) | ('F' << 16) | (' ' << 24))) #endif int daedalus_parse_file(struct ffmpeg_loader *fm, const char *path) { AVFormatContext *fmt_ctx = NULL; const AVCodec *codec = NULL; AVPacket *pkt = NULL; int video_stream = -1; int ret; fmt_ctx = fm->avformat_alloc_context(); if (!fmt_ctx) { log_err("avformat_alloc_context returned NULL"); return -ENOMEM; } ret = fm->avformat_open_input(&fmt_ctx, path, NULL, NULL); if (ret < 0) { log_err("avformat_open_input(%s): code %d", path, ret); return -EIO; } ret = fm->avformat_find_stream_info(fmt_ctx, NULL); if (ret < 0) { log_err("avformat_find_stream_info: code %d", ret); fm->avformat_close_input(&fmt_ctx); return -EIO; } video_stream = fm->av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &codec, 0); if (video_stream < 0) { log_err("no video stream found in %s", path); fm->avformat_close_input(&fmt_ctx); return -ENOENT; } { AVStream *st = fmt_ctx->streams[video_stream]; log_info("video stream #%d: codec=%s (%s) %dx%d, %d/%d fps", video_stream, codec ? codec->name : "?", codec ? codec->long_name : "?", st->codecpar->width, st->codecpar->height, st->avg_frame_rate.num, st->avg_frame_rate.den); } pkt = fm->av_packet_alloc(); if (!pkt) { log_err("av_packet_alloc returned NULL"); fm->avformat_close_input(&fmt_ctx); return -ENOMEM; } int n_frames = 0, n_keyframes = 0; size_t total_bytes = 0; while ((ret = fm->av_read_frame(fmt_ctx, pkt)) >= 0) { if (pkt->stream_index == video_stream) { n_frames++; total_bytes += pkt->size; if (pkt->flags & AV_PKT_FLAG_KEY) n_keyframes++; log_debug("frame %d: size=%d pts=%lld dts=%lld flags=0x%x", n_frames, pkt->size, (long long) pkt->pts, (long long) pkt->dts, pkt->flags); } fm->av_packet_unref(pkt); } if (ret != AVERROR_EOF) { log_warn("av_read_frame terminated abnormally (code %d)", ret); } log_info("parse complete: %d frames (%d key) total %zu bytes", n_frames, n_keyframes, total_bytes); fm->av_packet_free(&pkt); fm->avformat_close_input(&fmt_ctx); return n_frames > 0 ? 0 : -ENODATA; }