X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=nageru%2Fffmpeg_capture.cpp;h=c8b87fee9628fa67776350f619768468d8e91e97;hb=eaba7288c4fb39ca195c9355970293bcaf088dbc;hp=2ecdf64c4096d8db46f11d1eb185ed93f79d2ac0;hpb=b563b8903fa84bb7fd62d7d0b84b70cb26843dbf;p=nageru diff --git a/nageru/ffmpeg_capture.cpp b/nageru/ffmpeg_capture.cpp index 2ecdf64..c8b87fe 100644 --- a/nageru/ffmpeg_capture.cpp +++ b/nageru/ffmpeg_capture.cpp @@ -33,7 +33,7 @@ extern "C" { #include "flags.h" #include "image_input.h" #include "ref_counted_frame.h" -#include "timebase.h" +#include "shared/timebase.h" #define FRAME_SIZE (8 << 20) // 8 MB. @@ -134,7 +134,7 @@ AVPixelFormat decide_dst_format(AVPixelFormat src_format, bmusb::PixelFormat dst return av_get_pix_fmt(best_format); } -YCbCrFormat decode_ycbcr_format(const AVPixFmtDescriptor *desc, const AVFrame *frame) +YCbCrFormat decode_ycbcr_format(const AVPixFmtDescriptor *desc, const AVFrame *frame, bool is_mjpeg) { YCbCrFormat format; AVColorSpace colorspace = av_frame_get_colorspace(frame); @@ -198,6 +198,17 @@ YCbCrFormat decode_ycbcr_format(const AVPixFmtDescriptor *desc, const AVFrame *f break; } + if (is_mjpeg && !format.full_range) { + // Limited-range MJPEG is only detected by FFmpeg whenever a special + // JPEG comment is set, which means that in practice, the stream is + // almost certainly generated by Futatabi. Override FFmpeg's forced + // MJPEG defaults (it disregards the values set in the mux) with what + // Futatabi sets. + format.luma_coefficients = YCBCR_REC_709; + format.cb_x_position = 0.0; + format.cb_y_position = 0.5; + } + format.cr_x_position = format.cb_x_position; format.cr_y_position = format.cb_y_position; return format; @@ -365,10 +376,7 @@ bool FFmpegCapture::play_video(const string &pathname) last_modified = buf.st_mtim; } - AVDictionary *opts = nullptr; - av_dict_set(&opts, "fflags", "nobuffer", 0); - - auto format_ctx = avformat_open_input_unique(pathname.c_str(), nullptr, &opts, AVIOInterruptCB{ &FFmpegCapture::interrupt_cb_thunk, this }); + auto format_ctx = avformat_open_input_unique(pathname.c_str(), nullptr, nullptr, AVIOInterruptCB{ &FFmpegCapture::interrupt_cb_thunk, this }); if (format_ctx == nullptr) { fprintf(stderr, "%s: Error opening file\n", pathname.c_str()); return false; @@ -407,6 +415,9 @@ bool FFmpegCapture::play_video(const string &pathname) unique_ptr video_codec_ctx_cleanup( video_codec_ctx.get(), avcodec_close); + // Used in decode_ycbcr_format(). + is_mjpeg = video_codecpar->codec_id == AV_CODEC_ID_MJPEG; + // Open audio decoder, if we have audio. AVCodecContextWithDeleter audio_codec_ctx; if (audio_stream_index != -1) { @@ -851,7 +862,7 @@ UniqueFrame FFmpegCapture::make_video_frame(const AVFrame *frame, const string & video_frame->len = (width * 2) * height; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(sws_dst_format); - current_frame_ycbcr_format = decode_ycbcr_format(desc, frame); + current_frame_ycbcr_format = decode_ycbcr_format(desc, frame, is_mjpeg); } else { assert(pixel_format == bmusb::PixelFormat_8BitYCbCrPlanar); const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(sws_dst_format); @@ -870,7 +881,7 @@ UniqueFrame FFmpegCapture::make_video_frame(const AVFrame *frame, const string & video_frame->len = width * height + 2 * chroma_width * chroma_height; - current_frame_ycbcr_format = decode_ycbcr_format(desc, frame); + current_frame_ycbcr_format = decode_ycbcr_format(desc, frame, is_mjpeg); } sws_scale(sws_ctx.get(), frame->data, frame->linesize, 0, frame->height, pic_data, linesizes);