]> git.sesse.net Git - nageru/commitdiff
Pull the file muxing out of the HTTPD. (It was pretty ugly all along.)
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 17 Apr 2016 19:46:15 +0000 (21:46 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 17 Apr 2016 20:04:18 +0000 (22:04 +0200)
h264encode.cpp
h264encode.h
httpd.cpp
httpd.h
mixer.cpp

index 7bb0f8469a4b8c4daaa5a6551255afc55657e7c5..b329c983969e2f6696795f7afe53410ef2ff6484 100644 (file)
@@ -198,6 +198,8 @@ public:
        bool begin_frame(GLuint *y_tex, GLuint *cbcr_tex);
        RefCountedGLsync end_frame(int64_t pts, const vector<RefCountedFrame> &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<float> &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<Mux> 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<float> &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();
+}
index 43a56c609c147448d834751b5e81a89bcf9c1cdc..527074e297bbb759506dbe18f028bd994365c7d5 100644 (file)
@@ -53,6 +53,10 @@ public:
        RefCountedGLsync end_frame(int64_t pts, const std::vector<RefCountedFrame> &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<H264EncoderImpl> impl;
 };
index 7375e8a09db1d597f0a2988975019d709b7276a9..6bf436478b8df8cd9afb83301b0ec6a330f808c7 100644 (file)
--- 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<mutex> 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 d5c805c0741f588df61e73ceecb999b3bcba0d01..55a81c20e59ffa125ef59a28320e98aa0f34c494 100644 (file)
--- 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<Stream *> streams;  // Not owned.
 
        int width, height;
-       std::unique_ptr<Mux> file_mux;  // To local disk.
 };
 
 #endif  // !defined(_HTTPD_H)
index 081bad513d689e02cce914c1fd18e535afc16393..3dc8a4c3e5c3630965106755c38f6e4a1373c865 100644 (file)
--- 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