summaryrefslogtreecommitdiffstats
path: root/libhb/encx265.c
diff options
context:
space:
mode:
authorRodeo <[email protected]>2014-02-10 17:38:41 +0000
committerRodeo <[email protected]>2014-02-10 17:38:41 +0000
commite1e76b53cd11e7706e884d802c5985633b849e4f (patch)
tree64630e6611b46ee27a7ba8804f96a8fce1524ab2 /libhb/encx265.c
parente22ffd488a656f6534ce93f85dcfdb8fdb7976bd (diff)
Initial x265 integration. Patch by Zhang Zhiqiang. Thanks!
Build with --enable-x265 (requires CMake). Use via HandBrakeCLI with -a none -e x265 -f raw Only raw HEVC output is supported for now (no audio or subtitles). git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@6023 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'libhb/encx265.c')
-rw-r--r--libhb/encx265.c295
1 files changed, 295 insertions, 0 deletions
diff --git a/libhb/encx265.c b/libhb/encx265.c
new file mode 100644
index 000000000..afb6ef9e2
--- /dev/null
+++ b/libhb/encx265.c
@@ -0,0 +1,295 @@
+/* encx265.c
+
+ Copyright (c) 2003-2013 HandBrake Team
+ This file is part of the HandBrake source code
+ Homepage: <http://handbrake.fr/>.
+ It may be used under the terms of the GNU General Public License v2.
+ For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html
+ */
+#ifdef USE_X265
+#include <stdarg.h>
+#include <time.h>
+
+#include "hb.h"
+#include "hb_dict.h"
+#include "x265.h"
+
+int encx265Init( hb_work_object_t *, hb_job_t * );
+int encx265Work( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** );
+void encx265Close( hb_work_object_t * );
+void writeNALs(hb_work_private_t *, const x265_nal *, int );
+
+hb_work_object_t hb_encx265 =
+{
+ WORK_ENCX265,
+ "H.265/HEVC encoder (libx265)",
+ encx265Init,
+ encx265Work,
+ encx265Close
+};
+
+#define FRAME_INFO_MAX2 (8) // 2^8 = 256; 90000/256 = 352 frames/sec
+#define FRAME_INFO_MIN2 (17) // 2^17 = 128K; 90000/131072 = 1.4 frames/sec
+#define FRAME_INFO_SIZE (1 << (FRAME_INFO_MIN2 - FRAME_INFO_MAX2 + 1))
+#define FRAME_INFO_MASK (FRAME_INFO_SIZE - 1)
+
+static const char * const hb_x265_encopt_synonyms[][2] =
+{
+ { "me", "motion", },
+ { NULL, NULL, },
+};
+
+struct hb_work_private_s
+{
+ hb_job_t * job;
+ x265_encoder * x265;
+ x265_param * param;
+ x265_picture pic_in;
+ x265_nal * p_nal;
+ uint32_t nal_count;
+ uint8_t * grey_data;
+
+ uint32_t frames_in;
+ uint32_t frames_out;
+ int chap_mark; // saved chap mark when we're propagating it
+ int64_t last_stop; // Debugging - stop time of previous input frame
+ int64_t next_chap;
+
+ struct {
+ int64_t duration;
+ } frame_info[FRAME_INFO_SIZE];
+
+ int i_type;
+ int numEncode;
+ int64_t i_pts;
+
+ FILE *fout;
+};
+
+/***********************************************************************
+ * hb_work_encx265_init
+ ***********************************************************************
+ *
+ **********************************************************************/
+int encx265Init( 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;
+ pv->fout = fopen(job->file, "wb");
+ fseek(pv->fout, 0, SEEK_SET);
+
+ x265_param *param = pv->param = x265_param_alloc();
+
+ x265_param_default_preset(param, "medium", "psnr");
+
+ hb_log("Output video resolution: %dx%d", job->width, job->height);
+ param->sourceWidth = job->width;
+ param->sourceHeight = job->height;
+ param->frameRate = job->vrate/job->vrate_base;
+ param->poolNumThreads = hb_get_cpu_count();
+
+ param->logLevel = X265_LOG_INFO;
+ param->frameNumThreads = hb_get_cpu_count();
+ param->tuQTMaxInterDepth = 1;
+ param->tuQTMaxIntraDepth = 1;
+
+ hb_dict_t *x265_opts = NULL;
+ if (job->advanced_opts != NULL && *job->advanced_opts != '\0')
+ {
+ x265_opts = hb_encopts_to_dict(job->advanced_opts, job->vcodec);
+ }
+ /* iterate through x265_opts and parse the options */
+ int ret;
+ hb_dict_entry_t *entry = NULL;
+ while ((entry = hb_dict_next(x265_opts, entry)) != NULL)
+ {
+
+ ret = x265_param_parse( param, entry->key, entry->value );
+ /* Let x265 sanity check the options for us */
+ if( ret == X265_PARAM_BAD_NAME )
+ hb_log( "x265 options: Unknown suboption %s", entry->key );
+ if( ret == X265_PARAM_BAD_VALUE )
+ hb_log( "x265 options: Bad argument %s=%s", entry->key, entry->value ? entry->value : "(null)" );
+
+ }
+ hb_dict_free(&x265_opts);
+
+ param->subpelRefine = 1;
+ param->maxNumMergeCand = 1;
+ param->bEnablePsnr = 1;
+
+ if (job->vquality > 0)
+ param->rc.qp = (int)job->vquality;
+
+ param->rc.bitrate = job->vbitrate;
+
+ x265_setup_primitives(param, 0);
+
+ pv->x265 = x265_encoder_open( param );
+ if ( pv->x265 == NULL )
+ {
+ hb_error("encx265: x265_encoder_open failed.");
+ free( pv );
+ pv = NULL;
+ return 1;
+ }
+ pv->numEncode = 0;
+ if (!x265_encoder_headers(pv->x265, &pv->p_nal, &pv->nal_count))
+ {
+ writeNALs(pv, pv->p_nal, pv->nal_count);
+ }
+ x265_picture_init(param, &pv->pic_in);
+ return 0;
+}
+
+void encx265Close( hb_work_object_t * w )
+{
+ hb_work_private_t * pv = w->private_data;
+
+ x265_param_free(pv->param);
+ x265_encoder_close(pv->x265);
+ fclose(pv->fout);
+ free(pv);
+ w->private_data = NULL;
+}
+
+/*
+ * see comments in definition of 'frame_info' in pv struct for description
+ * of what these routines are doing.
+ */
+static void save_frame_info( hb_work_private_t * pv, hb_buffer_t * in )
+{
+ int i = (in->s.start >> FRAME_INFO_MAX2) & FRAME_INFO_MASK;
+ pv->frame_info[i].duration = in->s.stop - in->s.start;
+}
+
+void writeNALs(hb_work_private_t * pv, const x265_nal* nal, int nalcount)
+{
+ int i;
+ for (i = 0; i < nalcount; i++)
+ {
+ fwrite((const char*)nal->payload, 1, nal->sizeBytes, pv->fout);
+ nal++;
+ }
+}
+
+static hb_buffer_t *x265_encode( hb_work_object_t *w, hb_buffer_t *in )
+{
+ hb_work_private_t *pv = w->private_data;
+ hb_job_t *job = pv->job;
+
+ x265_picture pic_out;
+ int numEncode;
+
+ pv->pic_in.stride[0] = in->plane[0].stride;
+ pv->pic_in.stride[1] = in->plane[1].stride;
+ pv->pic_in.stride[2] = in->plane[2].stride;
+ pv->pic_in.planes[0] = in->plane[0].data;
+ pv->pic_in.planes[1] = in->plane[1].data;
+ pv->pic_in.planes[2] = in->plane[2].data;
+ pv->pic_in.bitDepth = 8;
+
+ if( in->s.new_chap && job->chapter_markers )
+ {
+ pv->i_type = X265_TYPE_IDR;
+ if( pv->next_chap == 0 )
+ {
+ pv->next_chap = in->s.start;
+ pv->chap_mark = in->s.new_chap;
+ }
+ in->s.new_chap = 0;
+ }
+ else
+ {
+ pv->i_type = X265_TYPE_AUTO;
+ }
+
+ if( pv->last_stop != in->s.start )
+ {
+ hb_log("encx265 input continuity err: last stop %"PRId64" start %"PRId64,
+ pv->last_stop, in->s.start);
+ }
+ pv->last_stop = in->s.stop;
+
+ save_frame_info( pv, in );
+
+ pv->pic_in.pts = in->s.start;
+ numEncode = x265_encoder_encode( pv->x265, &pv->p_nal, &pv->nal_count, &pv->pic_in, &pic_out );
+ pv->numEncode += numEncode;
+ if ( pv->nal_count > 0 )
+ writeNALs(pv, pv->p_nal, pv->nal_count);
+
+ return NULL;
+}
+
+int encx265Work( hb_work_object_t * w, hb_buffer_t ** buf_in,
+ hb_buffer_t ** buf_out )
+{
+ hb_work_private_t *pv = w->private_data;
+ hb_buffer_t *in = *buf_in;
+ int numEncode;
+
+ *buf_out = NULL;
+ if (in->size <= 0)
+ {
+ x265_picture pic_out;
+ uint32_t i_nal;
+ x265_nal *nal;
+ x265_stats stats;
+ hb_buffer_t *last_buf = NULL;
+ while (1)
+ {
+ numEncode = x265_encoder_encode(pv->x265, &nal, &i_nal, NULL, &pic_out);
+ if (i_nal <= 0)
+ break;
+ pv->numEncode += numEncode;
+ writeNALs(pv, nal, i_nal);
+
+ }
+ // Flushed everything - add the eof to the end of the chain.
+ if ( last_buf == NULL )
+ *buf_out = in;
+ else
+ last_buf->next = in;
+
+
+ *buf_in = NULL;
+
+ x265_encoder_get_stats(pv->x265, &stats, sizeof(stats));
+ x265_encoder_close(pv->x265);
+
+ if (stats.encodedPictureCount)
+ {
+ hb_log("X265 encoded %d frames in %.2fs (%.2f fps), %.2f kb/s, ", stats.encodedPictureCount,
+ stats.elapsedEncodeTime, stats.encodedPictureCount / stats.elapsedEncodeTime, stats.bitrate);
+
+ hb_log("Global PSNR: %.3f\n", stats.globalPsnr);
+ }
+ else
+ hb_log("encoded 0 frames\n");
+
+ hb_log("Work done!");
+ exit(0);
+
+ return HB_WORK_DONE;
+ }
+
+ pv->pic_in.poc = pv->frames_in;
+ ++pv->frames_in;
+ ++pv->frames_out;
+ *buf_out = x265_encode( w, in );
+ return HB_WORK_OK;
+}
+
+const char * hb_x265_encopt_name(const char *name)
+{
+ int i;
+ for (i = 0; hb_x265_encopt_synonyms[i][0] != NULL; i++)
+ if (!strcmp(name, hb_x265_encopt_synonyms[i][1]))
+ return hb_x265_encopt_synonyms[i][0];
+ return name;
+}
+
+#endif