return buf_size;
}
+namespace {
+
+void add_video_stream(AVFormatContext *avctx)
+{
+ AVStream *stream = avformat_new_stream(avctx, nullptr);
+ if (stream == nullptr) {
+ fprintf(stderr, "avformat_new_stream() failed\n");
+ abort();
+ }
+
+ // FFmpeg is very picky about having audio at 1/48000 timebase,
+ // no matter what we write. Even though we'd prefer our usual 1/120000,
+ // put the video on the same one, so that we can have locked audio.
+ stream->time_base = AVRational{ 1, OUTPUT_FREQUENCY };
+ stream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
+ stream->codecpar->codec_id = AV_CODEC_ID_MJPEG;
+
+ // Used for aspect ratio only. Can change without notice (the mux won't care).
+ stream->codecpar->width = global_flags.width;
+ stream->codecpar->height = global_flags.height;
+
+ // TODO: We could perhaps use the interpretation for each card here
+ // (or at least the command-line flags) instead of the defaults,
+ // but what would we do when they change?
+ stream->codecpar->color_primaries = AVCOL_PRI_BT709;
+ stream->codecpar->color_trc = AVCOL_TRC_IEC61966_2_1;
+ stream->codecpar->color_space = AVCOL_SPC_BT709;
+ stream->codecpar->color_range = AVCOL_RANGE_MPEG;
+ stream->codecpar->chroma_location = AVCHROMA_LOC_LEFT;
+ stream->codecpar->field_order = AV_FIELD_PROGRESSIVE;
+}
+
+void add_audio_stream(AVFormatContext *avctx)
+{
+ AVStream *stream = avformat_new_stream(avctx, nullptr);
+ if (stream == nullptr) {
+ fprintf(stderr, "avformat_new_stream() failed\n");
+ abort();
+ }
+ stream->time_base = AVRational{ 1, OUTPUT_FREQUENCY };
+ stream->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
+ stream->codecpar->codec_id = AV_CODEC_ID_PCM_S32LE;
+ stream->codecpar->channel_layout = AV_CH_LAYOUT_STEREO;
+ stream->codecpar->channels = 2;
+ stream->codecpar->sample_rate = OUTPUT_FREQUENCY;
+}
+
+void finalize_mux(AVFormatContext *avctx)
+{
+ AVDictionary *options = NULL;
+ vector<pair<string, string>> opts = MUX_OPTS;
+ for (pair<string, string> opt : opts) {
+ av_dict_set(&options, opt.first.c_str(), opt.second.c_str(), 0);
+ }
+ if (avformat_write_header(avctx, &options) < 0) {
+ fprintf(stderr, "avformat_write_header() failed\n");
+ abort();
+ }
+}
+
+} // namespace
+
MJPEGEncoder::MJPEGEncoder(HTTPD *httpd, const string &va_display)
: httpd(httpd)
{
avctx->flags = AVFMT_FLAG_CUSTOM_IO;
for (unsigned card_idx = 0; card_idx < global_flags.card_to_mjpeg_stream_export.size(); ++card_idx) {
- AVStream *stream = avformat_new_stream(avctx.get(), nullptr);
- if (stream == nullptr) {
- fprintf(stderr, "avformat_new_stream() failed\n");
- abort();
- }
-
- // FFmpeg is very picky about having audio at 1/48000 timebase,
- // no matter what we write. Even though we'd prefer our usual 1/120000,
- // put the video on the same one, so that we can have locked audio.
- stream->time_base = AVRational{ 1, OUTPUT_FREQUENCY };
- stream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
- stream->codecpar->codec_id = AV_CODEC_ID_MJPEG;
-
- // Used for aspect ratio only. Can change without notice (the mux won't care).
- stream->codecpar->width = global_flags.width;
- stream->codecpar->height = global_flags.height;
-
- // TODO: We could perhaps use the interpretation for each card here
- // (or at least the command-line flags) instead of the defaults,
- // but what would we do when they change?
- stream->codecpar->color_primaries = AVCOL_PRI_BT709;
- stream->codecpar->color_trc = AVCOL_TRC_IEC61966_2_1;
- stream->codecpar->color_space = AVCOL_SPC_BT709;
- stream->codecpar->color_range = AVCOL_RANGE_MPEG;
- stream->codecpar->chroma_location = AVCHROMA_LOC_LEFT;
- stream->codecpar->field_order = AV_FIELD_PROGRESSIVE;
+ add_video_stream(avctx.get());
}
for (unsigned card_idx = 0; card_idx < global_flags.card_to_mjpeg_stream_export.size(); ++card_idx) {
- AVStream *stream = avformat_new_stream(avctx.get(), nullptr);
- if (stream == nullptr) {
- fprintf(stderr, "avformat_new_stream() failed\n");
- abort();
- }
- stream->time_base = AVRational{ 1, OUTPUT_FREQUENCY };
- stream->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
- stream->codecpar->codec_id = AV_CODEC_ID_PCM_S32LE;
- stream->codecpar->channel_layout = AV_CH_LAYOUT_STEREO;
- stream->codecpar->channels = 2;
- stream->codecpar->sample_rate = OUTPUT_FREQUENCY;
- }
-
- AVDictionary *options = NULL;
- vector<pair<string, string>> opts = MUX_OPTS;
- for (pair<string, string> opt : opts) {
- av_dict_set(&options, opt.first.c_str(), opt.second.c_str(), 0);
- }
- if (avformat_write_header(avctx.get(), &options) < 0) {
- fprintf(stderr, "avformat_write_header() failed\n");
- abort();
+ add_audio_stream(avctx.get());
}
+ finalize_mux(avctx.get());
// Initialize VA-API.
string error;