]> git.sesse.net Git - nageru/blobdiff - h264encode.cpp
Move WIDTH/HEIGHT #defines into defs.h.
[nageru] / h264encode.cpp
index a16a5ea0b376dc4ed5678a48b7c4417ef433533e..d20683518784fd51c1a15d8089b46e26d7981678 100644 (file)
@@ -155,6 +155,20 @@ typedef struct __bitstream bitstream;
 
 using namespace std;
 
+// Supposedly vaRenderPicture() is supposed to destroy the buffer implicitly,
+// but if we don't delete it here, we get leaks. The GStreamer implementation
+// does the same.
+static void render_picture_and_delete(VADisplay dpy, VAContextID context, VABufferID *buffers, int num_buffers)
+{
+    VAStatus va_status = vaRenderPicture(dpy, context, buffers, num_buffers);
+    CHECK_VASTATUS(va_status, "vaRenderPicture");
+
+    for (int i = 0; i < num_buffers; ++i) {
+        va_status = vaDestroyBuffer(va_dpy, buffers[i]);
+        CHECK_VASTATUS(va_status, "vaDestroyBuffer");
+    }
+}
+
 static unsigned int 
 va_swap32(unsigned int val)
 {
@@ -1371,8 +1385,7 @@ static int render_sequence(void)
     render_id[0] = seq_param_buf;
     render_id[1] = rc_param_buf;
     
-    va_status = vaRenderPicture(va_dpy, context_id, &render_id[0], 2);
-    CHECK_VASTATUS(va_status, "vaRenderPicture");;
+    render_picture_and_delete(va_dpy, context_id, &render_id[0], 2);
 
     if (misc_priv_type != 0) {
         va_status = vaCreateBuffer(va_dpy, context_id,
@@ -1385,7 +1398,7 @@ static int render_sequence(void)
         misc_param_tmp->data[0] = misc_priv_value;
         vaUnmapBuffer(va_dpy, misc_param_tmpbuf);
     
-        va_status = vaRenderPicture(va_dpy, context_id, &misc_param_tmpbuf, 1);
+        render_picture_and_delete(va_dpy, context_id, &misc_param_tmpbuf, 1);
     }
     
     return 0;
@@ -1464,16 +1477,9 @@ static int render_picture(void)
 
     va_status = vaCreateBuffer(va_dpy, context_id, VAEncPictureParameterBufferType,
                                sizeof(pic_param), 1, &pic_param, &pic_param_buf);
-    CHECK_VASTATUS(va_status, "vaCreateBuffer");;
-
-    va_status = vaRenderPicture(va_dpy, context_id, &pic_param_buf, 1);
-    CHECK_VASTATUS(va_status, "vaRenderPicture");
+    CHECK_VASTATUS(va_status, "vaCreateBuffer");
 
-    // Supposedly vaRenderPicture() is supposed to destroy the buffer implicitly,
-    // but if we don't delete it here, we get leaks. The GStreamer implementation
-    // does the same.
-    va_status = vaDestroyBuffer(va_dpy, pic_param_buf);
-    CHECK_VASTATUS(va_status, "vaDestroyBuffer");
+    render_picture_and_delete(va_dpy, context_id, &pic_param_buf, 1);
 
     return 0;
 }
@@ -1508,8 +1514,7 @@ static int render_packedsequence(void)
 
     render_id[0] = packedseq_para_bufid;
     render_id[1] = packedseq_data_bufid;
-    va_status = vaRenderPicture(va_dpy, context_id, render_id, 2);
-    CHECK_VASTATUS(va_status, "vaRenderPicture");
+    render_picture_and_delete(va_dpy, context_id, render_id, 2);
 
     free(packedseq_buffer);
     
@@ -1546,8 +1551,7 @@ static int render_packedpicture(void)
 
     render_id[0] = packedpic_para_bufid;
     render_id[1] = packedpic_data_bufid;
-    va_status = vaRenderPicture(va_dpy, context_id, render_id, 2);
-    CHECK_VASTATUS(va_status, "vaRenderPicture");
+    render_picture_and_delete(va_dpy, context_id, render_id, 2);
 
     free(packedpic_buffer);
     
@@ -1583,8 +1587,7 @@ static void render_packedslice()
 
     render_id[0] = packedslice_para_bufid;
     render_id[1] = packedslice_data_bufid;
-    va_status = vaRenderPicture(va_dpy, context_id, render_id, 2);
-    CHECK_VASTATUS(va_status, "vaRenderPicture");
+    render_picture_and_delete(va_dpy, context_id, render_id, 2);
 
     free(packedslice_buffer);
 }
@@ -1643,21 +1646,14 @@ static int render_slice(void)
                                sizeof(slice_param), 1, &slice_param, &slice_param_buf);
     CHECK_VASTATUS(va_status, "vaCreateBuffer");
 
-    va_status = vaRenderPicture(va_dpy, context_id, &slice_param_buf, 1);
-    CHECK_VASTATUS(va_status, "vaRenderPicture");
-
-    // Supposedly vaRenderPicture() is supposed to destroy the buffer implicitly,
-    // but if we don't delete it here, we get leaks. The GStreamer implementation
-    // does the same.
-    va_status = vaDestroyBuffer(va_dpy, slice_param_buf);
-    CHECK_VASTATUS(va_status, "vaDestroyBuffer");
+    render_picture_and_delete(va_dpy, context_id, &slice_param_buf, 1);
 
     return 0;
 }
 
 
 
-int H264Encoder::save_codeddata(storage_task task)
+void H264Encoder::save_codeddata(storage_task task)
 {    
     VACodedBufferSegment *buf_list = NULL;
     VAStatus va_status;
@@ -1694,13 +1690,13 @@ int H264Encoder::save_codeddata(storage_task task)
         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.
-    // (They can never be queued to us after the video frame they belong to, only before.)
     for ( ;; ) {
         int64_t audio_pts;
         std::vector<float> audio;
         {
              unique_lock<mutex> lock(frame_queue_mutex);
-             if (pending_audio_frames.empty()) break;
+             frame_queue_nonempty.wait(lock, [this]{ return copy_thread_should_quit || !pending_audio_frames.empty(); });
+             if (copy_thread_should_quit) return;
              auto it = pending_audio_frames.begin();
              if (it->first > task.pts) break;
              audio_pts = it->first;
@@ -1738,6 +1734,7 @@ int H264Encoder::save_codeddata(storage_task task)
         // TODO: Delayed frames.
         avcodec_free_frame(&frame);
         av_free_packet(&pkt);
+        if (audio_pts == task.pts) break;
     }
 
 #if 0
@@ -1759,8 +1756,6 @@ int H264Encoder::save_codeddata(storage_task task)
     printf("%08lld", encode_order);
     printf("(%06d bytes coded)", coded_size);
 #endif
-
-    return 0;
 }
 
 
@@ -1908,7 +1903,7 @@ H264Encoder::~H264Encoder()
        {
                unique_lock<mutex> lock(frame_queue_mutex);
                copy_thread_should_quit = true;
-               frame_queue_nonempty.notify_one();
+               frame_queue_nonempty.notify_all();
        }
        storage_thread.join();
        copy_thread.join();
@@ -1987,10 +1982,9 @@ void H264Encoder::add_audio(int64_t pts, std::vector<float> audio)
                unique_lock<mutex> lock(frame_queue_mutex);
                pending_audio_frames[pts] = move(audio);
        }
-       frame_queue_nonempty.notify_one();
+       frame_queue_nonempty.notify_all();
 }
 
-
 void H264Encoder::end_frame(RefCountedGLsync fence, int64_t pts, const std::vector<RefCountedFrame> &input_frames)
 {
        {
@@ -1998,7 +1992,7 @@ void H264Encoder::end_frame(RefCountedGLsync fence, int64_t pts, const std::vect
                pending_video_frames[current_storage_frame] = PendingFrame{ fence, input_frames, pts };
                ++current_storage_frame;
        }
-       frame_queue_nonempty.notify_one();
+       frame_queue_nonempty.notify_all();
 }
 
 void H264Encoder::copy_thread_func()