#include <vector>
#include "bmusb/bmusb.h"
-#include "ffmpeg_raii.h"
+#include "shared/ffmpeg_raii.h"
#include "ffmpeg_util.h"
#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.
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);
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;
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;
unique_ptr<AVCodecContext, decltype(avcodec_close)*> 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) {
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);
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);