]> git.sesse.net Git - nageru/blobdiff - video_encoder.cpp
Move the entire stream mux logic from QuickSyncEncoder into VideoEncoder.
[nageru] / video_encoder.cpp
index 39bc2641932dce864a6a0c7ba5e18feb80ae677d..8fd9723239f613345151fb11323371be19497728 100644 (file)
@@ -1,8 +1,13 @@
 #include "video_encoder.h"
 
+#include <assert.h>
+
 #include <string>
 
 #include "defs.h"
+#include "flags.h"
+#include "httpd.h"
+#include "timebase.h"
 #include "quicksync_encoder.h"
 
 using namespace std;
@@ -31,13 +36,16 @@ string generate_local_dump_filename(int frame)
 VideoEncoder::VideoEncoder(QSurface *surface, const std::string &va_display, int width, int height, HTTPD *httpd)
        : surface(surface), va_display(va_display), width(width), height(height), httpd(httpd)
 {
-       quicksync_encoder.reset(new QuickSyncEncoder(surface, va_display, width, height, httpd));
+       open_output_stream();
+
+       quicksync_encoder.reset(new QuickSyncEncoder(surface, va_display, width, height, stream_mux.get()));
        quicksync_encoder->open_output_file(generate_local_dump_filename(/*frame=*/0).c_str());
 }
 
 VideoEncoder::~VideoEncoder()
 {
        quicksync_encoder.reset(nullptr);
+       close_output_stream();
 }
 
 void VideoEncoder::do_cut(int frame)
@@ -46,7 +54,7 @@ void VideoEncoder::do_cut(int frame)
        printf("Starting new recording: %s\n", filename.c_str());
        quicksync_encoder->close_output_file();
        quicksync_encoder->shutdown();
-       quicksync_encoder.reset(new QuickSyncEncoder(surface, va_display, width, height, httpd));
+       quicksync_encoder.reset(new QuickSyncEncoder(surface, va_display, width, height, stream_mux.get()));
        quicksync_encoder->open_output_file(filename.c_str());
 }
 
@@ -64,3 +72,69 @@ RefCountedGLsync VideoEncoder::end_frame(int64_t pts, int64_t duration, const st
 {
        return quicksync_encoder->end_frame(pts, duration, input_frames);
 }
+
+void VideoEncoder::open_output_stream()
+{
+       AVFormatContext *avctx = avformat_alloc_context();
+       AVOutputFormat *oformat = av_guess_format(global_flags.stream_mux_name.c_str(), nullptr, nullptr);
+       assert(oformat != nullptr);
+       avctx->oformat = oformat;
+
+       string codec_name;
+       int bit_rate;
+
+       if (global_flags.stream_audio_codec_name.empty()) {
+               codec_name = AUDIO_OUTPUT_CODEC_NAME;
+               bit_rate = DEFAULT_AUDIO_OUTPUT_BIT_RATE;
+       } else {
+               codec_name = global_flags.stream_audio_codec_name;
+               bit_rate = global_flags.stream_audio_codec_bitrate;
+       }
+
+       uint8_t *buf = (uint8_t *)av_malloc(MUX_BUFFER_SIZE);
+       avctx->pb = avio_alloc_context(buf, MUX_BUFFER_SIZE, 1, this, nullptr, &VideoEncoder::write_packet_thunk, nullptr);
+
+       Mux::Codec video_codec;
+       if (global_flags.uncompressed_video_to_http) {
+               video_codec = Mux::CODEC_NV12;
+       } else {
+               video_codec = Mux::CODEC_H264;
+       }
+
+       avctx->flags = AVFMT_FLAG_CUSTOM_IO;
+       AVCodec *codec_audio = avcodec_find_encoder_by_name(codec_name.c_str());
+       if (codec_audio == nullptr) {
+               fprintf(stderr, "ERROR: Could not find codec '%s'\n", codec_name.c_str());
+               exit(1);
+       }
+
+       int time_base = global_flags.stream_coarse_timebase ? COARSE_TIMEBASE : TIMEBASE;
+       stream_mux_writing_header = true;
+       stream_mux.reset(new Mux(avctx, width, height, video_codec, codec_audio, time_base, bit_rate, this));
+       stream_mux_writing_header = false;
+       httpd->set_header(stream_mux_header);
+       stream_mux_header.clear();
+}
+
+void VideoEncoder::close_output_stream()
+{
+       stream_mux.reset();
+}
+
+int VideoEncoder::write_packet_thunk(void *opaque, uint8_t *buf, int buf_size)
+{
+       VideoEncoder *video_encoder = (VideoEncoder *)opaque;
+       return video_encoder->write_packet(buf, buf_size);
+}
+
+int VideoEncoder::write_packet(uint8_t *buf, int buf_size)
+{
+       if (stream_mux_writing_header) {
+               stream_mux_header.append((char *)buf, buf_size);
+       } else {
+               httpd->add_data((char *)buf, buf_size, stream_mux_writing_keyframes);
+               stream_mux_writing_keyframes = false;
+       }
+       return buf_size;
+}
+