X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=ffmpeg_capture.cpp;h=407f359104cff8444ac56cc9480c77c86366667c;hb=d42c974620e7b0f780c0d4d10a3ce8f34e8e912a;hp=464b4cb92d292b8b6bb80f458c92715209f6e902;hpb=73ddb883aaf76a76d8c03730e587ac396255c0c9;p=nageru diff --git a/ffmpeg_capture.cpp b/ffmpeg_capture.cpp index 464b4cb..407f359 100644 --- a/ffmpeg_capture.cpp +++ b/ffmpeg_capture.cpp @@ -28,6 +28,7 @@ extern "C" { #include "bmusb/bmusb.h" #include "ffmpeg_raii.h" +#include "ffmpeg_util.h" #include "flags.h" #include "image_input.h" @@ -65,6 +66,8 @@ FFmpegCapture::FFmpegCapture(const string &filename, unsigned width, unsigned he { // Not really used for anything. description = "Video: " + filename; + + avformat_network_init(); // In case someone wants this. } FFmpegCapture::~FFmpegCapture() @@ -135,12 +138,14 @@ void FFmpegCapture::producer_thread_func() string pathname = search_for_file(filename); if (filename.empty()) { fprintf(stderr, "%s not found, sleeping one second and trying again...\n", filename.c_str()); + send_disconnected_frame(); producer_thread_should_quit.sleep_for(seconds(1)); continue; } if (!play_video(pathname)) { // Error. fprintf(stderr, "Error when playing %s, sleeping one second and trying again...\n", pathname.c_str()); + send_disconnected_frame(); producer_thread_should_quit.sleep_for(seconds(1)); continue; } @@ -154,6 +159,28 @@ void FFmpegCapture::producer_thread_func() } } +void FFmpegCapture::send_disconnected_frame() +{ + // Send an empty frame to signal that we have no signal anymore. + FrameAllocator::Frame video_frame = video_frame_allocator->alloc_frame(); + if (video_frame.data) { + VideoFormat video_format; + video_format.width = width; + video_format.height = height; + video_format.stride = width * 4; + video_format.frame_rate_nom = 60; + video_format.frame_rate_den = 1; + video_format.is_connected = false; + + video_frame.len = width * height * 4; + memset(video_frame.data, 0, video_frame.len); + + frame_callback(timecode++, + video_frame, /*video_offset=*/0, video_format, + FrameAllocator::Frame(), /*audio_offset=*/0, AudioFormat()); + } +} + bool FFmpegCapture::play_video(const string &pathname) { // Note: Call before open, not after; otherwise, there's a race. @@ -179,25 +206,14 @@ bool FFmpegCapture::play_video(const string &pathname) return false; } - int video_stream_index = -1, audio_stream_index = -1; - AVRational video_timebase{ 1, 1 }; - for (unsigned i = 0; i < format_ctx->nb_streams; ++i) { - if (format_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && - video_stream_index == -1) { - video_stream_index = i; - video_timebase = format_ctx->streams[i]->time_base; - } - if (format_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && - audio_stream_index == -1) { - audio_stream_index = i; - } - } + int video_stream_index = find_stream_index(format_ctx.get(), AVMEDIA_TYPE_VIDEO); if (video_stream_index == -1) { fprintf(stderr, "%s: No video stream found\n", pathname.c_str()); return false; } const AVCodecParameters *codecpar = format_ctx->streams[video_stream_index]->codecpar; + AVRational video_timebase = format_ctx->streams[video_stream_index]->time_base; AVCodecContextWithDeleter codec_ctx = avcodec_alloc_context3_unique(nullptr); if (avcodec_parameters_to_context(codec_ctx.get(), codecpar) < 0) { fprintf(stderr, "%s: Cannot fill codec parameters\n", pathname.c_str()); @@ -307,7 +323,7 @@ bool FFmpegCapture::play_video(const string &pathname) if (sws_ctx == nullptr || sws_last_width != frame->width || sws_last_height != frame->height) { sws_ctx.reset( sws_getContext(frame->width, frame->height, (AVPixelFormat)frame->format, - width, height, AV_PIX_FMT_RGBA, + width, height, AV_PIX_FMT_BGRA, SWS_BICUBIC, nullptr, nullptr, nullptr)); sws_last_width = frame->width; sws_last_height = frame->height; @@ -323,6 +339,11 @@ bool FFmpegCapture::play_video(const string &pathname) video_format.stride = width * 4; video_format.frame_rate_nom = video_timebase.den; video_format.frame_rate_den = av_frame_get_pkt_duration(frame.get()) * video_timebase.num; + if (video_format.frame_rate_nom == 0 || video_format.frame_rate_den == 0) { + // Invalid frame rate. + video_format.frame_rate_nom = 60; + video_format.frame_rate_den = 1; + } video_format.has_signal = true; video_format.is_connected = true;