summaryrefslogtreecommitdiffstats
path: root/libhb/enctheora.c
diff options
context:
space:
mode:
Diffstat (limited to 'libhb/enctheora.c')
-rw-r--r--libhb/enctheora.c170
1 files changed, 170 insertions, 0 deletions
diff --git a/libhb/enctheora.c b/libhb/enctheora.c
new file mode 100644
index 000000000..3773b708a
--- /dev/null
+++ b/libhb/enctheora.c
@@ -0,0 +1,170 @@
+/* This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.m0k.org/>.
+ It may be used under the terms of the GNU General Public License. */
+
+#include "hb.h"
+#include "theora/theora.h"
+
+int enctheoraInit( hb_work_object_t *, hb_job_t * );
+int enctheoraWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** );
+void enctheoraClose( hb_work_object_t * );
+
+hb_work_object_t hb_enctheora =
+{
+ WORK_ENCTHEORA,
+ "Theora encoder (libtheora)",
+ enctheoraInit,
+ enctheoraWork,
+ enctheoraClose
+};
+
+struct hb_work_private_s
+{
+ hb_job_t * job;
+
+ theora_state theora;
+};
+
+int enctheoraInit( hb_work_object_t * w, hb_job_t * job )
+{
+ hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );
+ w->private_data = pv;
+
+ pv->job = job;
+
+ theora_info ti;
+ theora_comment tc;
+ ogg_packet op;
+ theora_info_init( &ti );
+
+ ti.width = ti.frame_width = job->width;
+ ti.height = ti.frame_height = job->height;
+ ti.offset_x = ti.offset_y = 0;
+ ti.fps_numerator = job->vrate;
+ ti.fps_denominator = job->vrate_base;
+ if (job->pixel_ratio)
+ {
+ ti.aspect_numerator = job->pixel_aspect_width;
+ ti.aspect_denominator = job->pixel_aspect_height;
+ }
+ else
+ {
+ ti.aspect_numerator = ti.aspect_denominator = 1;
+ }
+ ti.colorspace = OC_CS_UNSPECIFIED;
+ ti.pixelformat = OC_PF_420;
+ ti.keyframe_auto_p = 1;
+ ti.keyframe_frequency = (job->vrate / job->vrate_base) + 1;
+ ti.keyframe_frequency_force = (10 * job->vrate / job->vrate_base) + 1;
+ /* From encoder_example.c */
+ ti.quick_p = 1;
+ ti.dropframes_p = 0;
+ ti.keyframe_auto_threshold = 80;
+ ti.keyframe_mindistance = 8;
+ ti.noise_sensitivity = 1;
+ ti.sharpness = 0;
+ if (job->vquality < 0.0 || job->vquality > 1.0)
+ {
+ ti.target_bitrate = job->vbitrate * 1000;
+ ti.keyframe_data_target_bitrate = job->vbitrate * 1000 * 1.5;
+ ti.quality = 0;
+ }
+ else
+ {
+ ti.target_bitrate = 0;
+ ti.quality = 63 * job->vquality;
+ }
+
+ theora_encode_init( &pv->theora, &ti );
+ theora_info_clear( &ti );
+
+ theora_encode_header( &pv->theora, &op );
+ memcpy(w->config->theora.headers[0], &op, sizeof(op));
+ memcpy(w->config->theora.headers[0] + sizeof(op), op.packet, op.bytes );
+
+ theora_comment_init(&tc);
+ theora_encode_comment(&tc,&op);
+ memcpy(w->config->theora.headers[1], &op, sizeof(op));
+ memcpy(w->config->theora.headers[1] + sizeof(op), op.packet, op.bytes );
+ free(op.packet);
+
+ theora_encode_tables(&pv->theora, &op);
+ memcpy(w->config->theora.headers[2], &op, sizeof(op));
+ memcpy(w->config->theora.headers[2] + sizeof(op), op.packet, op.bytes );
+
+ return 0;
+}
+
+/***********************************************************************
+ * Close
+ ***********************************************************************
+ *
+ **********************************************************************/
+void enctheoraClose( hb_work_object_t * w )
+{
+ hb_work_private_t * pv = w->private_data;
+ /* TODO: Free alloc'd */
+
+ free( pv );
+ w->private_data = NULL;
+}
+
+/***********************************************************************
+ * Work
+ ***********************************************************************
+ *
+ **********************************************************************/
+int enctheoraWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
+ hb_buffer_t ** buf_out )
+{
+ hb_work_private_t * pv = w->private_data;
+ hb_job_t * job = pv->job;
+ hb_buffer_t * in = *buf_in, * buf;
+ yuv_buffer yuv;
+ ogg_packet op;
+ static int last_p = 0;
+
+ memset(&op, 0, sizeof(op));
+ memset(&yuv, 0, sizeof(yuv));
+
+ /* If this is the last empty frame, we're done */
+ if(!in->data)
+ {
+ if (!last_p)
+ {
+ last_p++;
+ goto finish;
+ }
+ *buf_out = NULL;
+ return HB_WORK_DONE;
+ }
+
+ yuv.y_width = job->width;
+ yuv.y_height = job->height;
+ yuv.y_stride = job->width;
+
+ yuv.uv_width = job->width / 2;
+ yuv.uv_height = job->height / 2;
+ yuv.uv_stride = job->width / 2;
+
+ yuv.y = in->data;
+ yuv.u = in->data + job->width * job->height;
+ yuv.v = in->data + job->width * job->height * 5/4;
+
+ theora_encode_YUVin(&pv->theora, &yuv);
+
+finish:
+ theora_encode_packetout(&pv->theora, last_p, &op);
+
+ buf = hb_buffer_init( op.bytes + sizeof(op) );
+ memcpy(buf->data, &op, sizeof(op));
+ memcpy(buf->data + sizeof(op), op.packet, op.bytes);
+ buf->frametype = ( theora_packet_iskeyframe(&op) ) ? HB_FRAME_KEY : HB_FRAME_REF;
+ buf->start = in->start;
+ buf->stop = in->stop;
+
+ *buf_out = buf;
+
+ return HB_WORK_OK;
+}
+