theme_main_chain.setup_chain();
//theme_main_chain.chain->enable_phase_timing(true);
+ const int64_t av_delay = lrint(global_flags.audio_queue_length_ms * 0.001 * TIMEBASE); // Corresponds to the delay in ResamplingQueue.
GLuint y_tex, cbcr_tex;
- bool got_frame = video_encoder->begin_frame(&y_tex, &cbcr_tex);
+ bool got_frame = video_encoder->begin_frame(pts_int + av_delay, duration, theme_main_chain.input_frames, &y_tex, &cbcr_tex);
assert(got_frame);
// Render main chain.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- const int64_t av_delay = lrint(global_flags.audio_queue_length_ms * 0.001 * TIMEBASE); // Corresponds to the delay in ResamplingQueue.
- RefCountedGLsync fence = video_encoder->end_frame(pts_int + av_delay, duration, theme_main_chain.input_frames);
+ RefCountedGLsync fence = video_encoder->end_frame();
// The live frame just shows the RGBA texture we just rendered.
// It owns rgba_tex now.
}
}
-bool QuickSyncEncoderImpl::begin_frame(GLuint *y_tex, GLuint *cbcr_tex)
+bool QuickSyncEncoderImpl::begin_frame(int64_t pts, int64_t duration, const vector<RefCountedFrame> &input_frames, GLuint *y_tex, GLuint *cbcr_tex)
{
assert(!is_shutdown);
GLSurface *surf = nullptr;
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, surf->cbcr_egl_image);
}
+ current_video_frame = PendingFrame{ {}, input_frames, pts, duration };
+
return true;
}
file_audio_encoder->encode_audio(audio, pts + global_delay());
}
-RefCountedGLsync QuickSyncEncoderImpl::end_frame(int64_t pts, int64_t duration, const vector<RefCountedFrame> &input_frames)
+RefCountedGLsync QuickSyncEncoderImpl::end_frame()
{
assert(!is_shutdown);
{
unique_lock<mutex> lock(frame_queue_mutex);
- pending_video_frames.push(PendingFrame{ fence, input_frames, pts, duration });
+ current_video_frame.fence = fence;
+ pending_video_frames.push(move(current_video_frame));
++current_storage_frame;
}
frame_queue_nonempty.notify_all();
impl->add_audio(pts, audio);
}
-bool QuickSyncEncoder::begin_frame(GLuint *y_tex, GLuint *cbcr_tex)
+bool QuickSyncEncoder::begin_frame(int64_t pts, int64_t duration, const vector<RefCountedFrame> &input_frames, GLuint *y_tex, GLuint *cbcr_tex)
{
- return impl->begin_frame(y_tex, cbcr_tex);
+ return impl->begin_frame(pts, duration, input_frames, y_tex, cbcr_tex);
}
-RefCountedGLsync QuickSyncEncoder::end_frame(int64_t pts, int64_t duration, const vector<RefCountedFrame> &input_frames)
+RefCountedGLsync QuickSyncEncoder::end_frame()
{
- return impl->end_frame(pts, duration, input_frames);
+ return impl->end_frame();
}
void QuickSyncEncoder::shutdown()
void set_stream_mux(Mux *mux); // Does not take ownership. Must be called unless x264 is used for the stream.
void add_audio(int64_t pts, std::vector<float> audio);
- bool begin_frame(GLuint *y_tex, GLuint *cbcr_tex);
- RefCountedGLsync end_frame(int64_t pts, int64_t duration, const std::vector<RefCountedFrame> &input_frames);
+ bool begin_frame(int64_t pts, int64_t duration, const std::vector<RefCountedFrame> &input_frames, GLuint *y_tex, GLuint *cbcr_tex);
+ RefCountedGLsync end_frame();
void shutdown(); // Blocking. Does not require an OpenGL context.
void release_gl_resources(); // Requires an OpenGL context. Must be run after shutdown.
int64_t global_delay() const; // So we never get negative dts.
QuickSyncEncoderImpl(const std::string &filename, movit::ResourcePool *resource_pool, QSurface *surface, const std::string &va_display, int width, int height, AVOutputFormat *oformat, X264Encoder *x264_encoder, DiskSpaceEstimator *disk_space_estimator);
~QuickSyncEncoderImpl();
void add_audio(int64_t pts, std::vector<float> audio);
- bool begin_frame(GLuint *y_tex, GLuint *cbcr_tex);
- RefCountedGLsync end_frame(int64_t pts, int64_t duration, const std::vector<RefCountedFrame> &input_frames);
+ bool begin_frame(int64_t pts, int64_t duration, const std::vector<RefCountedFrame> &input_frames, GLuint *y_tex, GLuint *cbcr_tex);
+ RefCountedGLsync end_frame();
void shutdown();
void release_gl_resources();
void set_stream_mux(Mux *mux)
int current_storage_frame;
+ PendingFrame current_video_frame; // Used only between begin_frame() and end_frame().
std::queue<PendingFrame> pending_video_frames; // under frame_queue_mutex
movit::ResourcePool *resource_pool;
QSurface *surface;
stream_audio_encoder->encode_audio(audio, pts + quicksync_encoder->global_delay());
}
-bool VideoEncoder::begin_frame(GLuint *y_tex, GLuint *cbcr_tex)
+bool VideoEncoder::begin_frame(int64_t pts, int64_t duration, const std::vector<RefCountedFrame> &input_frames, GLuint *y_tex, GLuint *cbcr_tex)
{
lock_guard<mutex> lock(qs_mu);
qs_needing_cleanup.clear(); // Since we have an OpenGL context here, and are called regularly.
- return quicksync_encoder->begin_frame(y_tex, cbcr_tex);
+ return quicksync_encoder->begin_frame(pts, duration, input_frames, y_tex, cbcr_tex);
}
-RefCountedGLsync VideoEncoder::end_frame(int64_t pts, int64_t duration, const std::vector<RefCountedFrame> &input_frames)
+RefCountedGLsync VideoEncoder::end_frame()
{
lock_guard<mutex> lock(qs_mu);
- return quicksync_encoder->end_frame(pts, duration, input_frames);
+ return quicksync_encoder->end_frame();
}
void VideoEncoder::open_output_stream()
~VideoEncoder();
void add_audio(int64_t pts, std::vector<float> audio);
- bool begin_frame(GLuint *y_tex, GLuint *cbcr_tex);
- RefCountedGLsync end_frame(int64_t pts, int64_t duration, const std::vector<RefCountedFrame> &input_frames);
+
+ // Allocate a frame to render into. The returned two textures
+ // are yours to render into (build them into an FBO).
+ // Call end_frame() when you're done.
+ bool begin_frame(int64_t pts, int64_t duration, const std::vector<RefCountedFrame> &input_frames, GLuint *y_tex, GLuint *cbcr_tex);
+
+ // Call after you are done rendering into the frame; at this point,
+ // y_tex and cbcr_tex will be assumed done, and handed over to the
+ // encoder. The returned fence is purely a convenience; you do not
+ // need to use it for anything, but it's useful if you wanted to set
+ // one anyway.
+ RefCountedGLsync end_frame();
// Does a cut of the disk stream immediately ("frame" is used for the filename only).
void do_cut(int frame);