5#include <libavcodec/avcodec.h>
6#include <libavformat/avformat.h>
7#include <libavutil/imgutils.h>
8#include <libavutil/opt.h>
9#include <libavutil/pixdesc.h>
10#include <libswscale/swscale.h>
53 uint32_t target_width,
54 uint32_t target_height,
65 const AVCodec* codec =
nullptr;
67 reinterpret_cast<const void**
>(&codec));
80 if (avcodec_parameters_to_context(
codec_context, stream->codecpar) < 0) {
92#ifdef MAYAFLUX_PLATFORM_WINDOWS
93 uint32_t probed_width = 0;
94 uint32_t probed_height = 0;
97 AVPacket* probe_pkt = av_packet_alloc();
98 AVFrame* probe_frm = av_frame_alloc();
100 if (probe_pkt && probe_frm) {
104 while (!probed && av_read_frame(fmt, probe_pkt) >= 0) {
106 av_packet_unref(probe_pkt);
112 && probe_frm->format != AV_PIX_FMT_NONE) {
113 codec_context->pix_fmt =
static_cast<AVPixelFormat
>(probe_frm->format);
115 probed_width =
static_cast<uint32_t
>(probe_frm->width);
116 probed_height =
static_cast<uint32_t
>(probe_frm->height);
118 av_frame_unref(probe_frm);
121 av_packet_unref(probe_pkt);
125 av_packet_free(&probe_pkt);
126 av_frame_free(&probe_frm);
133 if (probed_width > 0 && probed_height > 0) {
134 width = probed_width;
145 && stream->r_frame_rate.den > 0
146 && stream->r_frame_rate.num > 0) {
148 }
else if (stream->avg_frame_rate.den > 0 && stream->avg_frame_rate.num > 0) {
150 }
else if (stream->r_frame_rate.den > 0 && stream->r_frame_rate.num > 0) {
156 if (stream->nb_frames > 0) {
157 total_frames =
static_cast<uint64_t
>(stream->nb_frames);
158 }
else if (stream->duration != AV_NOPTS_VALUE
159 && stream->time_base.num > 0 && stream->time_base.den > 0
161 double dur =
static_cast<double>(stream->duration) * av_q2d(stream->time_base);
165 /
static_cast<double>(AV_TIME_BASE);
170 "[VideoStreamContext] stream #{} | "
171 "avg_frame_rate={}/{} ({:.6f} fps) | "
172 "r_frame_rate={}/{} ({:.6f} fps) | "
173 "chosen frame_rate={:.6f} fps | "
175 "stream duration={} (tb={}/{}, => {:.4f}s) | "
176 "format duration={} (=> {:.4f}s) | "
180 stream->avg_frame_rate.num, stream->avg_frame_rate.den,
181 (stream->avg_frame_rate.den > 0 ? av_q2d(stream->avg_frame_rate) : 0.0),
182 stream->r_frame_rate.num, stream->r_frame_rate.den,
183 (stream->r_frame_rate.den > 0 ? av_q2d(stream->r_frame_rate) : 0.0),
185 static_cast<int64_t
>(stream->nb_frames),
187 stream->time_base.num, stream->time_base.den,
188 (stream->duration != AV_NOPTS_VALUE && stream->time_base.den > 0
189 ?
static_cast<double>(stream->duration) * av_q2d(stream->time_base)
193 ?
static_cast<double>(demux.
format_context->duration) / AV_TIME_BASE
196 (stream->nb_frames > 0 ?
"nb_frames"
197 : (stream->duration != AV_NOPTS_VALUE ?
"stream_duration*fps"
198 :
"format_duration*fps")));
209 uint32_t tw, uint32_t th,
int tf)
219 const AVCodec* codec =
nullptr;
221 reinterpret_cast<const void**
>(&codec));
234 if (avcodec_parameters_to_context(
codec_context, stream->codecpar) < 0) {
257 width =
static_cast<uint32_t
>(s->codecpar->width);
258 height =
static_cast<uint32_t
>(s->codecpar->height);
266#ifdef MAYAFLUX_PLATFORM_WINDOWS
276 if (stream->avg_frame_rate.den > 0 && stream->avg_frame_rate.num > 0)
278 else if (stream->r_frame_rate.den > 0 && stream->r_frame_rate.num > 0)
281 auto fmt = av_get_pix_fmt_name(
static_cast<AVPixelFormat
>(
src_pixel_format));
284 "[VideoStreamContext] open_device: stream #{} | {}x{} | pix_fmt={}",
295 uint32_t target_height,
302 m_last_error =
"setup_scaler: source pix_fmt is AV_PIX_FMT_NONE — "
303 "codec has not resolved its output format yet";
311 :
static_cast<int>(AV_PIX_FMT_RGBA);
314 static_cast<int>(
width),
321 nullptr,
nullptr,
nullptr);
328 const AVPixFmtDescriptor* desc = av_pix_fmt_desc_get(
332 for (
int c = 0; c < desc->nb_components; ++c)
333 bits += desc->comp[c].depth;
341 if (align_remainder != 0)
348 const AVFrame* frame,
349 uint32_t tw, uint32_t th,
int tf)
351 if (!frame || frame->width <= 0 || frame->height <= 0
352 || frame->format == AV_PIX_FMT_NONE) {
353 m_last_error =
"rebuild_scaler_from_frame: invalid frame";
358 codec_context->pix_fmt =
static_cast<AVPixelFormat
>(frame->format);
361 width =
static_cast<uint32_t
>(frame->width);
362 height =
static_cast<uint32_t
>(frame->height);
407 const char* pix_fmt_name = av_get_pix_fmt_name(
codec_context->pix_fmt);
409 out.
attributes[
"video_pixel_format"] = std::string(pix_fmt_name);
424 if (stream->sample_aspect_ratio.num > 0 && stream->sample_aspect_ratio.den > 0) {
425 out.
attributes[
"video_sar_num"] = stream->sample_aspect_ratio.num;
426 out.
attributes[
"video_sar_den"] = stream->sample_aspect_ratio.den;
429 AVDictionaryEntry* tag =
nullptr;
430 while ((tag = av_dict_get(stream->metadata,
"", tag, AV_DICT_IGNORE_SUFFIX)))
431 out.
attributes[std::string(
"video_stream_") + tag->key] = std::string(tag->value);
437 std::vector<FileRegion> regions;
445 AVPacket* pkt = av_packet_alloc();
451 if (pkt->stream_index ==
stream_index && (pkt->flags & AV_PKT_FLAG_KEY)) {
454 r.
name =
"keyframe_" + std::to_string(idx);
456 int64_t pts = pkt->pts != AV_NOPTS_VALUE ? pkt->pts : pkt->dts;
458 if (pts != AV_NOPTS_VALUE && stream->time_base.num > 0 && stream->time_base.den > 0)
459 ts =
static_cast<double>(pts) * av_q2d(stream->time_base);
461 uint64_t frame_pos = 0;
463 frame_pos =
static_cast<uint64_t
>(ts *
frame_rate);
471 regions.push_back(std::move(r));
474 av_packet_unref(pkt);
477 av_packet_free(&pkt);
#define MF_INFO(comp, ctx,...)
AVFormatContext * format_context
Owned; freed in destructor.
static void init_ffmpeg()
Initialise FFmpeg logging level once per process.
int find_best_stream(int media_type, const void **out_codec=nullptr) const
Find the best stream of the requested media type.
AVStream * get_stream(int index) const
Access a stream by index.
bool is_open() const
True if the format context is open and stream info was found.
RAII owner of a single AVFormatContext and associated demux state.
void flush_codec()
Flush codec internal buffers (call after a seek).
bool open_device(const FFmpegDemuxContext &demux, uint32_t target_width=0, uint32_t target_height=0, int target_format=-1)
Open codec only, without initialising the SwsContext scaler.
uint32_t target_width
Requested output width (0 = source).
std::vector< FileRegion > extract_keyframe_regions(const FFmpegDemuxContext &demux) const
Extract keyframe positions as FileRegion entries.
void close()
Release codec and scaler resources.
uint32_t target_height
Requested output height (0 = source).
double frame_rate
Average frame rate (fps).
bool setup_scaler(uint32_t target_width, uint32_t target_height, int target_format)
Allocate and initialise the SwsContext for pixel format conversion.
uint32_t out_height
Output height after scaling.
uint32_t height
Source height in pixels.
void extract_stream_metadata(const FFmpegDemuxContext &demux, FileMetadata &out) const
Populate stream-specific fields into an existing FileMetadata.
uint32_t width
Source width in pixels.
int src_pixel_format
Source AVPixelFormat.
int out_pixel_format
Output AVPixelFormat.
int out_linesize
Output row stride in bytes.
bool rebuild_scaler_from_frame(const AVFrame *frame, uint32_t target_width=0, uint32_t target_height=0, int target_format=-1)
Rebuild the SwsContext using the pixel format resolved from a live decoded frame.
SwsContext * sws_context
Owned; freed in destructor.
AVCodecContext * codec_context
Owned; freed in destructor.
int target_format
Requested AVPixelFormat (negative = RGBA).
uint32_t out_bytes_per_pixel
Bytes per pixel in output format.
uint32_t out_width
Output width after scaling.
bool open(const FFmpegDemuxContext &demux, uint32_t target_width=0, uint32_t target_height=0, int target_format=-1)
Open the video stream from an already-probed demux context.
@ FileIO
Filesystem I/O operations.
@ IO
Networking, file handling, streaming.
std::vector< uint64_t > start_coordinates
N-dimensional start position (e.g., frame, x, y)
std::string name
Human-readable name for the region.
std::string type
Region type identifier (e.g., "cue", "scene", "block")
std::unordered_map< std::string, std::any > attributes
Region-specific metadata.
std::vector< uint64_t > end_coordinates
N-dimensional end position (inclusive)
Generic region descriptor for any file type.