From: Steinar H. Gunderson Date: Sun, 17 Apr 2016 19:46:15 +0000 (+0200) Subject: Pull the file muxing out of the HTTPD. (It was pretty ugly all along.) X-Git-Tag: 1.3.0~93 X-Git-Url: https://git.sesse.net/?p=nageru;a=commitdiff_plain;h=e45ebd282e3c6c369475ef0987945eca62ef8f58 Pull the file muxing out of the HTTPD. (It was pretty ugly all along.) --- diff --git a/h264encode.cpp b/h264encode.cpp index 7bb0f84..b329c98 100644 --- a/h264encode.cpp +++ b/h264encode.cpp @@ -198,6 +198,8 @@ public: bool begin_frame(GLuint *y_tex, GLuint *cbcr_tex); RefCountedGLsync end_frame(int64_t pts, const vector &input_frames); void shutdown(); + void open_output_file(const std::string &filename); + void close_output_file(); private: struct storage_task { @@ -225,8 +227,7 @@ private: void storage_task_thread(); void encode_audio(const vector &audio, int64_t audio_pts, - AVCodecContext *ctx, - HTTPD::PacketDestination destination); + AVCodecContext *ctx); void storage_task_enqueue(storage_task task); void save_codeddata(storage_task task); int render_packedsequence(); @@ -335,6 +336,8 @@ private: int frame_height; int frame_width_mbaligned; int frame_height_mbaligned; + + unique_ptr file_mux; // To local disk. }; // Supposedly vaRenderPicture() is supposed to destroy the buffer implicitly, @@ -1621,8 +1624,12 @@ void H264EncoderImpl::save_codeddata(storage_task task) pkt.flags = 0; } //pkt.duration = 1; - httpd->add_packet(pkt, task.pts + global_delay(), task.dts + global_delay(), - global_flags.uncompressed_video_to_http ? HTTPD::DESTINATION_FILE_ONLY : HTTPD::DESTINATION_FILE_AND_HTTP); + if (file_mux) { + file_mux->add_packet(pkt, task.pts + global_delay(), task.dts + global_delay()); + } + if (!global_flags.uncompressed_video_to_http) { + httpd->add_packet(pkt, task.pts + global_delay(), task.dts + global_delay()); + } } // Encode and add all audio frames up to and including the pts of this video frame. for ( ;; ) { @@ -1639,7 +1646,7 @@ void H264EncoderImpl::save_codeddata(storage_task task) pending_audio_frames.erase(it); } - encode_audio(audio, audio_pts, context_audio, HTTPD::DESTINATION_FILE_AND_HTTP); + encode_audio(audio, audio_pts, context_audio); if (audio_pts == task.pts) break; } @@ -1648,8 +1655,7 @@ void H264EncoderImpl::save_codeddata(storage_task task) void H264EncoderImpl::encode_audio( const vector &audio, int64_t audio_pts, - AVCodecContext *ctx, - HTTPD::PacketDestination destination) + AVCodecContext *ctx) { audio_frame->nb_samples = audio.size() / 2; audio_frame->channel_layout = AV_CH_LAYOUT_STEREO; @@ -1693,7 +1699,10 @@ void H264EncoderImpl::encode_audio( if (got_output) { pkt.stream_index = 1; pkt.flags = AV_PKT_FLAG_KEY; - httpd->add_packet(pkt, audio_pts + global_delay(), audio_pts + global_delay(), destination); + if (file_mux) { + file_mux->add_packet(pkt, audio_pts + global_delay(), audio_pts + global_delay()); + } + httpd->add_packet(pkt, audio_pts + global_delay(), audio_pts + global_delay()); } // TODO: Delayed frames. av_frame_unref(audio_frame); @@ -2012,6 +2021,29 @@ void H264EncoderImpl::shutdown() is_shutdown = true; } +void H264EncoderImpl::open_output_file(const std::string &filename) +{ + AVFormatContext *avctx = avformat_alloc_context(); + avctx->oformat = av_guess_format(NULL, filename.c_str(), NULL); + assert(filename.size() < sizeof(avctx->filename) - 1); + strcpy(avctx->filename, filename.c_str()); + + string url = "file:" + filename; + int ret = avio_open2(&avctx->pb, url.c_str(), AVIO_FLAG_WRITE, &avctx->interrupt_callback, NULL); + if (ret < 0) { + char tmp[AV_ERROR_MAX_STRING_SIZE]; + fprintf(stderr, "%s: avio_open2() failed: %s\n", filename.c_str(), av_make_error_string(tmp, sizeof(tmp), ret)); + exit(1); + } + + file_mux.reset(new Mux(avctx, frame_width, frame_height, Mux::CODEC_H264, TIMEBASE)); +} + +void H264EncoderImpl::close_output_file() +{ + file_mux.reset(); +} + void H264EncoderImpl::encode_thread_func() { int64_t last_dts = -1; @@ -2095,7 +2127,7 @@ void H264EncoderImpl::add_packet_for_uncompressed_frame(int64_t pts, const uint8 pkt.size = frame_width * frame_height * 2; pkt.stream_index = 0; pkt.flags = AV_PKT_FLAG_KEY; - httpd->add_packet(pkt, pts, pts, HTTPD::DESTINATION_HTTP_ONLY); + httpd->add_packet(pkt, pts, pts); } namespace { @@ -2223,4 +2255,12 @@ void H264Encoder::shutdown() impl->shutdown(); } -// Real class. +void H264Encoder::open_output_file(const std::string &filename) +{ + impl->open_output_file(filename); +} + +void H264Encoder::close_output_file() +{ + impl->close_output_file(); +} diff --git a/h264encode.h b/h264encode.h index 43a56c6..527074e 100644 --- a/h264encode.h +++ b/h264encode.h @@ -53,6 +53,10 @@ public: RefCountedGLsync end_frame(int64_t pts, const std::vector &input_frames); void shutdown(); // Blocking. + // You can only have one going at the same time. + void open_output_file(const std::string &filename); + void close_output_file(); + private: std::unique_ptr impl; }; diff --git a/httpd.cpp b/httpd.cpp index 7375e8a..6bf4364 100644 --- a/httpd.cpp +++ b/httpd.cpp @@ -42,42 +42,14 @@ void HTTPD::start(int port) MHD_OPTION_END); } -void HTTPD::add_packet(const AVPacket &pkt, int64_t pts, int64_t dts, PacketDestination destination) +void HTTPD::add_packet(const AVPacket &pkt, int64_t pts, int64_t dts) { unique_lock lock(streams_mutex); - if (destination != DESTINATION_FILE_ONLY) { - for (Stream *stream : streams) { - stream->add_packet(pkt, pts, dts); - } - } - if (file_mux && destination != DESTINATION_HTTP_ONLY) { - file_mux->add_packet(pkt, pts, dts); + for (Stream *stream : streams) { + stream->add_packet(pkt, pts, dts); } } -void HTTPD::open_output_file(const string &filename) -{ - AVFormatContext *avctx = avformat_alloc_context(); - avctx->oformat = av_guess_format(NULL, filename.c_str(), NULL); - assert(filename.size() < sizeof(avctx->filename) - 1); - strcpy(avctx->filename, filename.c_str()); - - string url = "file:" + filename; - int ret = avio_open2(&avctx->pb, url.c_str(), AVIO_FLAG_WRITE, &avctx->interrupt_callback, NULL); - if (ret < 0) { - char tmp[AV_ERROR_MAX_STRING_SIZE]; - fprintf(stderr, "%s: avio_open2() failed: %s\n", filename.c_str(), av_make_error_string(tmp, sizeof(tmp), ret)); - exit(1); - } - - file_mux.reset(new Mux(avctx, width, height, Mux::CODEC_H264, TIMEBASE)); -} - -void HTTPD::close_output_file() -{ - file_mux.reset(); -} - int HTTPD::answer_to_connection_thunk(void *cls, MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, diff --git a/httpd.h b/httpd.h index d5c805c..55a81c2 100644 --- a/httpd.h +++ b/httpd.h @@ -1,8 +1,7 @@ #ifndef _HTTPD_H #define _HTTPD_H -// A class dealing with stream output, both to HTTP (thus the class name) -// and to local output files. Since we generally have very few outputs +// A class dealing with stream output to HTTP. Since we generally have very few outputs // (end clients are not meant to connect directly to our stream; it should be // transcoded by something else and then sent to a reflector), we don't need to // care a lot about performance. Thus, we solve this by the simplest possible @@ -31,19 +30,9 @@ extern "C" { class HTTPD { public: - enum PacketDestination { - DESTINATION_FILE_ONLY, - DESTINATION_HTTP_ONLY, - DESTINATION_FILE_AND_HTTP - }; - HTTPD(int width, int height); void start(int port); - void add_packet(const AVPacket &pkt, int64_t pts, int64_t dts, PacketDestination destination); - - // You can only have one going at the same time. - void open_output_file(const std::string &filename); - void close_output_file(); + void add_packet(const AVPacket &pkt, int64_t pts, int64_t dts); private: static int answer_to_connection_thunk(void *cls, MHD_Connection *connection, @@ -88,7 +77,6 @@ private: std::set streams; // Not owned. int width, height; - std::unique_ptr file_mux; // To local disk. }; #endif // !defined(_HTTPD_H) diff --git a/mixer.cpp b/mixer.cpp index 081bad5..3dc8a4c 100644 --- a/mixer.cpp +++ b/mixer.cpp @@ -148,7 +148,6 @@ Mixer::Mixer(const QSurfaceFormat &format, unsigned num_cards) limiter(OUTPUT_FREQUENCY), compressor(OUTPUT_FREQUENCY) { - httpd.open_output_file(generate_local_dump_filename(/*frame=*/0).c_str()); httpd.start(9095); CHECK(init_movit(MOVIT_SHADER_DIR, MOVIT_DEBUG_OFF)); @@ -178,6 +177,7 @@ Mixer::Mixer(const QSurfaceFormat &format, unsigned num_cards) display_chain->finalize(); h264_encoder.reset(new H264Encoder(h264_encoder_surface, global_flags.va_display, WIDTH, HEIGHT, &httpd)); + h264_encoder->open_output_file(generate_local_dump_filename(/*frame=*/0).c_str()); // First try initializing the PCI devices, then USB, until we have the desired number of cards. unsigned num_pci_devices = 0, num_usb_devices = 0; @@ -692,10 +692,10 @@ void Mixer::thread_func() if (should_cut.exchange(false)) { // Test and clear. string filename = generate_local_dump_filename(frame); printf("Starting new recording: %s\n", filename.c_str()); + h264_encoder->close_output_file(); h264_encoder->shutdown(); - httpd.close_output_file(); - httpd.open_output_file(filename.c_str()); h264_encoder.reset(new H264Encoder(h264_encoder_surface, global_flags.va_display, WIDTH, HEIGHT, &httpd)); + h264_encoder->open_output_file(filename.c_str()); } #if 0