diff options
Diffstat (limited to 'libhb/enctheora.c')
-rw-r--r-- | libhb/enctheora.c | 170 |
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; +} + |