diff options
author | saintdev <[email protected]> | 2008-03-20 02:40:02 +0000 |
---|---|---|
committer | saintdev <[email protected]> | 2008-03-20 02:40:02 +0000 |
commit | 3a3870d7ea1e81e1a145b1d555b9f0164860f9e3 (patch) | |
tree | 9243f518a3d3827ce2d85c28c4c426e22c780a6f /libhb | |
parent | 1cac31c9ed66396d3fc8a00e9fd75b5f56b000a0 (diff) |
Theora.
This adds the theora encoder to the Xcode project as well. It does not enable
anything in the Mac GUI, just allows it to build.
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@1350 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'libhb')
-rw-r--r-- | libhb/Jamfile | 2 | ||||
-rw-r--r-- | libhb/Makefile | 7 | ||||
-rw-r--r-- | libhb/common.h | 2 | ||||
-rw-r--r-- | libhb/enctheora.c | 170 | ||||
-rw-r--r-- | libhb/hb.c | 1 | ||||
-rw-r--r-- | libhb/hb.h | 1 | ||||
-rw-r--r-- | libhb/internal.h | 6 | ||||
-rw-r--r-- | libhb/muxmkv.c | 49 | ||||
-rw-r--r-- | libhb/muxogm.c | 106 | ||||
-rw-r--r-- | libhb/work.c | 4 |
10 files changed, 310 insertions, 38 deletions
diff --git a/libhb/Jamfile b/libhb/Jamfile index bcf4a5471..4f20701c6 100644 --- a/libhb/Jamfile +++ b/libhb/Jamfile @@ -11,7 +11,7 @@ ipodutil.cpp common.c hb.c ports.c scan.c work.c decmpeg2.c encavcodec.c update. demuxmpeg.c fifo.c render.c reader.c muxcommon.c muxmp4.c sync.c stream.c decsub.c deca52.c decdca.c encfaac.c declpcm.c encx264.c decavcodec.c encxvid.c muxavi.c enclame.c muxogm.c encvorbis.c dvd.c muxmkv.c deblock.c deinterlace.c -denoise.c detelecine.c lang.c ; +denoise.c detelecine.c lang.c enctheora.c ; Library libhb : $(LIBHB_SRC) ; diff --git a/libhb/Makefile b/libhb/Makefile index 5b193854b..fb05e5a50 100644 --- a/libhb/Makefile +++ b/libhb/Makefile @@ -21,7 +21,7 @@ ifeq ($(SYSTEM),Linux) LDFLAGS += -lpthread -lm -ldl endif -SRCS = common.c hb.c ports.c scan.c work.c decmpeg2.c encavcodec.c \ +SRCS = common.c hb.c ports.c scan.c work.c decmpeg2.c encavcodec.c enctheora.c \ update.c demuxmpeg.c fifo.c render.c reader.c muxcommon.c stream.c \ muxmp4.c sync.c decsub.c deca52.c decdca.c encfaac.c declpcm.c encx264.c \ decavcodec.c encxvid.c muxmkv.c muxavi.c enclame.c muxogm.c encvorbis.c \ @@ -39,7 +39,8 @@ CONTRIBS = ../contrib/lib/liba52.a ../contrib/lib/libavformat.a \ ../contrib/lib/libvorbisfile.a ../contrib/lib/libogg.a \ ../contrib/lib/libsamplerate.a ../contrib/lib/libx264.a \ ../contrib/lib/libxvidcore.a ../contrib/lib/libmp4v2.a \ - ../contrib/lib/libmkv.a ../contrib/lib/libswscale.a + ../contrib/lib/libmkv.a ../contrib/lib/libswscale.a \ + ../contrib/lib/libtheora.a else CONTRIBS = ../contrib/lib/liba52.a ../contrib/lib/libavformat.a \ ../contrib/lib/libavcodec.a ../contrib/lib/libavutil.a \ @@ -51,7 +52,7 @@ CONTRIBS = ../contrib/lib/liba52.a ../contrib/lib/libavformat.a \ ../contrib/lib/libogg.a ../contrib/lib/libsamplerate.a \ ../contrib/lib/libx264.a ../contrib/lib/libxvidcore.a \ ../contrib/lib/libmp4v2.a ../contrib/lib/libmkv.a \ - ../contrib/lib/libswscale.a + ../contrib/lib/libswscale.a ../contrib/lib/libtheora.a endif CFLAGS += -I../contrib/include -D__LIBHB__ -DUSE_PTHREAD -DHB_VERSION=\"$(HB_VERSION)\" -DHB_BUILD=$(HB_BUILD) $(SYSDEF) diff --git a/libhb/common.h b/libhb/common.h index 953c243be..aa4cfc084 100644 --- a/libhb/common.h +++ b/libhb/common.h @@ -160,6 +160,7 @@ struct hb_job_s #define HB_VCODEC_FFMPEG 0x000001 #define HB_VCODEC_XVID 0x000002 #define HB_VCODEC_X264 0x000004 +#define HB_VCODEC_THEORA 0x000008 int vcodec; float vquality; @@ -526,6 +527,7 @@ extern hb_work_object_t hb_render; extern hb_work_object_t hb_encavcodec; extern hb_work_object_t hb_encxvid; extern hb_work_object_t hb_encx264; +extern hb_work_object_t hb_enctheora; extern hb_work_object_t hb_deca52; extern hb_work_object_t hb_decdca; extern hb_work_object_t hb_decavcodec; 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; +} + diff --git a/libhb/hb.c b/libhb/hb.c index fd02d06c9..62fe9c4f5 100644 --- a/libhb/hb.c +++ b/libhb/hb.c @@ -216,6 +216,7 @@ hb_handle_t * hb_init_dl( int verbose, int update_check ) hb_register( &hb_encavcodec ); hb_register( &hb_encxvid ); hb_register( &hb_encx264 ); + hb_register( &hb_enctheora ); hb_register( &hb_deca52 ); hb_register( &hb_decdca ); hb_register( &hb_decavcodec ); diff --git a/libhb/hb.h b/libhb/hb.h index 8324ca5f5..7454b634b 100644 --- a/libhb/hb.h +++ b/libhb/hb.h @@ -25,6 +25,7 @@ hb_register( &hb_render ); \ hb_register( &hb_encavcodec ); \ hb_register( &hb_encxvid ); \ hb_register( &hb_encx264 ); \ +hb_register( &hb_enctheora ); \ hb_register( &hb_deca52 ); \ hb_register( &hb_decdca ); \ hb_register( &hb_decavcodec ); \ diff --git a/libhb/internal.h b/libhb/internal.h index 8dfc3afac..a2b479929 100644 --- a/libhb/internal.h +++ b/libhb/internal.h @@ -166,6 +166,11 @@ union hb_esconfig_u struct { + uint8_t headers[3][HB_CONFIG_MAX_SIZE]; + } theora; + + struct + { uint8_t bytes[HB_CONFIG_MAX_SIZE]; int length; } aac; @@ -199,6 +204,7 @@ enum WORK_ENCAVCODEC, WORK_ENCXVID, WORK_ENCX264, + WORK_ENCTHEORA, WORK_DECA52, WORK_DECDCA, WORK_DECAVCODEC, diff --git a/libhb/muxmkv.c b/libhb/muxmkv.c index 58de30fa1..6ed6a6dec 100644 --- a/libhb/muxmkv.c +++ b/libhb/muxmkv.c @@ -106,6 +106,28 @@ static int MKVInit( hb_mux_object_t * m ) track->codecPrivate = job->config.mpeg4.bytes; track->codecPrivateSize = job->config.mpeg4.length; break; + case HB_VCODEC_THEORA: + { + int i; + uint64_t cp_size = 0; + track->codecID = MK_VCODEC_THEORA; + uint64_t header_sizes[3]; + for (i = 0; i < 3; ++i) + { + ogg_headers[i] = (ogg_packet *)job->config.theora.headers[i]; + ogg_headers[i]->packet = (unsigned char *)&job->config.theora.headers[i] + sizeof( ogg_packet ); + header_sizes[i] = ogg_headers[i]->bytes; + } + track->codecPrivate = mk_laceXiph(header_sizes, 2, &cp_size); + track->codecPrivate = realloc(track->codecPrivate, cp_size + ogg_headers[0]->bytes + ogg_headers[1]->bytes + ogg_headers[2]->bytes); + for(i = 0; i < 3; ++i) + { + memcpy(track->codecPrivate + cp_size, ogg_headers[i]->packet, ogg_headers[i]->bytes); + cp_size += ogg_headers[i]->bytes; + } + track->codecPrivateSize = cp_size; + } + break; default: *job->die = 1; hb_error("muxmkv: Unknown video codec: %x", job->vcodec); @@ -177,7 +199,7 @@ static int MKVInit( hb_mux_object_t * m ) { track->codecPrivate = NULL; track->codecPrivateSize = 0; - track->codecID = MK_ACODEC_AC3; + track->codecID = MK_ACODEC_AC3; } else { @@ -224,12 +246,14 @@ static int MKVInit( hb_mux_object_t * m ) static int MKVMux( hb_mux_object_t * m, hb_mux_data_t * mux_data, hb_buffer_t * buf ) { + ogg_packet *op = NULL; hb_job_t * job = m->job; hb_title_t * title = job->title; uint64_t timecode = 0; hb_chapter_t *chapter_data; char tmp_buffer[1024]; char *string = tmp_buffer; + if (mux_data == job->mux_data) { /* Video */ @@ -264,6 +288,21 @@ static int MKVMux( hb_mux_object_t * m, hb_mux_data_t * mux_data, } mux_data->prev_chapter_tc = timecode; } + + if (job->vcodec == HB_VCODEC_THEORA) + { + /* ughhh, theora is a pain :( */ + op = (ogg_packet *)buf->data; + op->packet = buf->data + sizeof( ogg_packet ); + if (mk_startFrame(m->file, mux_data->track) < 0) + { + hb_error( "Failed to write frame to output file, Disk Full?" ); + *job->die = 1; + } + mk_addFrameData(m->file, mux_data->track, op->packet, op->bytes); + mk_setFrameFlags(m->file, mux_data->track, timecode, 1); + return 0; + } } else { @@ -272,11 +311,13 @@ static int MKVMux( hb_mux_object_t * m, hb_mux_data_t * mux_data, if (job->acodec == HB_ACODEC_VORBIS) { /* ughhh, vorbis is a pain :( */ - ogg_packet *op; - op = (ogg_packet *)buf->data; op->packet = buf->data + sizeof( ogg_packet ); - mk_startFrame(m->file, mux_data->track); + if (mk_startFrame(m->file, mux_data->track)) + { + hb_error( "Failed to write frame to output file, Disk Full?" ); + *job->die = 1; + } mk_addFrameData(m->file, mux_data->track, op->packet, op->bytes); mk_setFrameFlags(m->file, mux_data->track, timecode, 1); return 0; diff --git a/libhb/muxogm.c b/libhb/muxogm.c index 16c2d4625..433122448 100644 --- a/libhb/muxogm.c +++ b/libhb/muxogm.c @@ -143,40 +143,57 @@ static int OGMInit( hb_mux_object_t * m ) /* First pass: all b_o_s packets */ - + hb_log("muxogm: Writing b_o_s header packets"); /* Video */ mux_data = job->mux_data; - memset( &h, 0, sizeof( ogg_stream_header_t ) ); - h.i_packet_type = 0x01; - memcpy( h.stream_type, "video ", 8 ); - if( mux_data->codec == HB_VCODEC_X264 ) - { - memcpy( h.sub_type, "H264", 4 ); - } - else if( mux_data->codec == HB_VCODEC_XVID ) + switch( job->vcodec ) { - memcpy( h.sub_type, "XVID", 4 ); - } - else - { - memcpy( h.sub_type, "DX50", 4 ); + case HB_VCODEC_THEORA: + memcpy(&op, job->config.theora.headers[0], sizeof(op)); + op.packet = job->config.theora.headers[0] + sizeof(op); + ogg_stream_packetin( &mux_data->os, &op ); + break; + case HB_VCODEC_XVID: + case HB_VCODEC_X264: + case HB_VCODEC_FFMPEG: + { + memset( &h, 0, sizeof( ogg_stream_header_t ) ); + h.i_packet_type = 0x01; + memcpy( h.stream_type, "video ", 8 ); + if( mux_data->codec == HB_VCODEC_X264 ) + { + memcpy( h.sub_type, "H264", 4 ); + } + else if( mux_data->codec == HB_VCODEC_XVID ) + { + memcpy( h.sub_type, "XVID", 4 ); + } + else + { + memcpy( h.sub_type, "DX50", 4 ); + } + SetDWLE( &h.i_size, sizeof( ogg_stream_header_t ) - 1); + SetQWLE( &h.i_time_unit, (int64_t) 10 * 1000 * 1000 * + (int64_t) job->vrate_base / (int64_t) job->vrate ); + SetQWLE( &h.i_samples_per_unit, 1 ); + SetDWLE( &h.i_default_len, 0 ); + SetDWLE( &h.i_buffer_size, 1024*1024 ); + SetWLE ( &h.i_bits_per_sample, 0 ); + SetDWLE( &h.header.video.i_width, job->width ); + SetDWLE( &h.header.video.i_height, job->height ); + op.packet = (unsigned char*)&h; + op.bytes = sizeof( ogg_stream_header_t ); + op.b_o_s = 1; + op.e_o_s = 0; + op.granulepos = 0; + op.packetno = mux_data->i_packet_no++; + ogg_stream_packetin( &mux_data->os, &op ); + break; + } + default: + hb_error( "muxogm: unhandled video codec" ); + *job->die = 1; } - SetDWLE( &h.i_size, sizeof( ogg_stream_header_t ) - 1); - SetQWLE( &h.i_time_unit, (int64_t) 10 * 1000 * 1000 * - (int64_t) job->vrate_base / (int64_t) job->vrate ); - SetQWLE( &h.i_samples_per_unit, 1 ); - SetDWLE( &h.i_default_len, 0 ); - SetDWLE( &h.i_buffer_size, 1024*1024 ); - SetWLE ( &h.i_bits_per_sample, 0 ); - SetDWLE( &h.header.video.i_width, job->width ); - SetDWLE( &h.header.video.i_height, job->height ); - op.packet = (unsigned char*)&h; - op.bytes = sizeof( ogg_stream_header_t ); - op.b_o_s = 1; - op.e_o_s = 0; - op.granulepos = 0; - op.packetno = mux_data->i_packet_no++; - ogg_stream_packetin( &mux_data->os, &op ); OGMFlush( m, mux_data ); /* Audio */ @@ -231,6 +248,30 @@ static int OGMInit( hb_mux_object_t * m ) } /* second pass: all non b_o_s packets */ + hb_log("muxogm: Writing non b_o_s header packets"); + /* Video */ + mux_data = job->mux_data; + switch( job->vcodec ) + { + case HB_VCODEC_THEORA: + for (i = 1; i < 3; i++) + { + memcpy(&op, job->config.theora.headers[i], sizeof(op)); + op.packet = job->config.theora.headers[i] + sizeof(op); + ogg_stream_packetin( &mux_data->os, &op ); + OGMFlush( m, mux_data ); + } + break; + case HB_VCODEC_XVID: + case HB_VCODEC_X264: + case HB_VCODEC_FFMPEG: + break; + default: + hb_error( "muxogm: unhandled video codec" ); + *job->die = 1; + } + + /* Audio */ for( i = 0; i < hb_list_count( title->list_audio ); i++ ) { audio = hb_list_item( title->list_audio, i ); @@ -263,6 +304,11 @@ static int OGMMux( hb_mux_object_t * m, hb_mux_data_t * mux_data, switch( mux_data->codec ) { + case HB_VCODEC_THEORA: + memcpy( &op, buf->data, sizeof( ogg_packet ) ); + op.packet = malloc( op.bytes ); + memcpy( op.packet, buf->data + sizeof( ogg_packet ), op.bytes ); + break; case HB_VCODEC_FFMPEG: case HB_VCODEC_XVID: case HB_VCODEC_X264: diff --git a/libhb/work.c b/libhb/work.c index c6357aeb6..9ebc33bf6 100644 --- a/libhb/work.c +++ b/libhb/work.c @@ -264,6 +264,10 @@ static void do_job( hb_job_t * job, int cpu_count ) hb_log( " + x264 options: %s", job->x264opts); w = getWork( WORK_ENCX264 ); break; + case HB_VCODEC_THEORA: + hb_log( " + encoder Theora" ); + w = getWork( WORK_ENCTHEORA ); + break; } w->fifo_in = job->fifo_render; w->fifo_out = job->fifo_mpeg4; |