diff options
author | sr55 <[email protected]> | 2013-09-06 17:11:27 +0000 |
---|---|---|
committer | sr55 <[email protected]> | 2013-09-06 17:11:27 +0000 |
commit | 10f5aec2de68e0f60a13c7696832e1a02dff187b (patch) | |
tree | a987ad5db3e0da36eb9757711764a3b59e7f7de7 | |
parent | f35cf60ca4a4b94f352afc22cc2252ffe7ff67d1 (diff) |
OpenCL: Merging Trunk to OpenCL Branch.
git-svn-id: svn://svn.handbrake.fr/HandBrake/branches/opencl@5770 b64f7644-9d1e-0410-96f1-a4d463321fa5
100 files changed, 13697 insertions, 3347 deletions
diff --git a/contrib/ffmpeg/A00-qsv.patch b/contrib/ffmpeg/A00-qsv.patch new file mode 100644 index 000000000..908033617 --- /dev/null +++ b/contrib/ffmpeg/A00-qsv.patch @@ -0,0 +1,2285 @@ +diff -Naur ../../libav-v9.6/configure ./configure +--- ../../libav-v9.6/configure 2013-05-12 08:39:07.000000000 +0200 ++++ ./configure 2013-08-14 10:48:00.520497159 +0200 +@@ -133,6 +133,7 @@ + --enable-vaapi enable VAAPI code + --enable-vda enable VDA code + --enable-vdpau enable VDPAU code ++ --enable-qsv enable QSV code + + Individual component options: + --disable-everything disable all components listed below +@@ -1076,6 +1077,7 @@ + vaapi + vda + vdpau ++ qsv + version3 + xmm_clobber_test + x11grab +@@ -1629,6 +1631,7 @@ + wmv3_dxva2_hwaccel_select="vc1_dxva2_hwaccel" + wmv3_vaapi_hwaccel_select="vc1_vaapi_hwaccel" + wmv3_vdpau_decoder_select="vc1_vdpau_decoder" ++h264_qsv_decoder_select="qsv h264_decoder" + + # parsers + h264_parser_select="error_resilience golomb h264dsp h264pred mpegvideo" +@@ -3584,6 +3587,12 @@ + check_cpp_condition vdpau/vdpau.h "defined VDP_DECODER_PROFILE_MPEG4_PART2_ASP" || + { echolog "Please upgrade to libvdpau >= 0.2 if you would like vdpau support." && disable vdpau; } + fi ++if enabled qsv; then ++ disable qsv ++ check_header msdk/mfxvideo.h && enable qsv ++else ++ disable qsv ++fi + + enabled debug && add_cflags -g"$debuglevel" && add_asflags -g"$debuglevel" + +@@ -3795,6 +3804,7 @@ + echo "libdxva2 enabled ${dxva2-no}" + echo "libva enabled ${vaapi-no}" + echo "libvdpau enabled ${vdpau-no}" ++echo "libqsv enabled ${qsv-no}" + echo "AVISynth enabled ${avisynth-no}" + echo "frei0r enabled ${frei0r-no}" + echo "gnutls enabled ${gnutls-no}" +diff -Naur ../../libav-v9.6/libavcodec/allcodecs.c ./libavcodec/allcodecs.c +--- ../../libav-v9.6/libavcodec/allcodecs.c 2013-05-12 08:39:07.000000000 +0200 ++++ ./libavcodec/allcodecs.c 2013-08-14 10:48:00.520497159 +0200 +@@ -143,6 +143,7 @@ + REGISTER_DECODER(H263I, h263i); + REGISTER_ENCODER(H263P, h263p); + REGISTER_DECODER(H264, h264); ++ REGISTER_DECODER(H264_QSV, h264_qsv); + REGISTER_DECODER(H264_VDPAU, h264_vdpau); + REGISTER_ENCDEC (HUFFYUV, huffyuv); + REGISTER_DECODER(IDCIN, idcin); +diff -Naur ../../libav-v9.6/libavcodec/Makefile ./libavcodec/Makefile +--- ../../libav-v9.6/libavcodec/Makefile 2013-05-12 08:39:07.000000000 +0200 ++++ ./libavcodec/Makefile 2013-08-14 10:48:00.521497282 +0200 +@@ -10,6 +10,7 @@ + vdpau.h \ + version.h \ + xvmc.h \ ++ qsv.h \ + + OBJS = allcodecs.o \ + audioconvert.o \ +@@ -196,6 +197,7 @@ + h264_loopfilter.o h264_direct.o \ + cabac.o h264_sei.o h264_ps.o \ + h264_refs.o h264_cavlc.o h264_cabac.o ++OBJS-$(CONFIG_H264_QSV_DECODER) += qsv_h264.o qsv.o + OBJS-$(CONFIG_H264_DXVA2_HWACCEL) += dxva2_h264.o + OBJS-$(CONFIG_H264_VAAPI_HWACCEL) += vaapi_h264.o + OBJS-$(CONFIG_H264_VDA_HWACCEL) += vda_h264.o +diff -Naur ../../libav-v9.6/libavcodec/qsv.c ./libavcodec/qsv.c +--- ../../libav-v9.6/libavcodec/qsv.c 1970-01-01 01:00:00.000000000 +0100 ++++ ./libavcodec/qsv.c 2013-08-19 21:32:01.704244071 +0200 +@@ -0,0 +1,646 @@ ++/* ********************************************************************* *\ ++ ++Copyright (C) 2013 Intel Corporation. All rights reserved. ++ ++Redistribution and use in source and binary forms, with or without ++modification, are permitted provided that the following conditions are met: ++- Redistributions of source code must retain the above copyright notice, ++this list of conditions and the following disclaimer. ++- Redistributions in binary form must reproduce the above copyright notice, ++this list of conditions and the following disclaimer in the documentation ++and/or other materials provided with the distribution. ++- Neither the name of Intel Corporation nor the names of its contributors ++may be used to endorse or promote products derived from this software ++without specific prior written permission. ++ ++THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION "AS IS" AND ANY EXPRESS OR ++IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, ++INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ ++\* ********************************************************************* */ ++ ++#include "qsv.h" ++ ++#include "avcodec.h" ++#include "internal.h" ++ ++int av_qsv_get_free_encode_task(av_qsv_list * tasks) ++{ ++ int ret = MFX_ERR_NOT_FOUND; ++ int i = 0; ++ if (tasks) ++ for (i = 0; i < av_qsv_list_count(tasks); i++) { ++ av_qsv_task *task = av_qsv_list_item(tasks, i); ++ if (task->stage && task->stage->out.sync) ++ if (!(*task->stage->out.sync->p_sync)) { ++ ret = i; ++ break; ++ } ++ } ++ return ret; ++} ++ ++int av_qsv_get_free_sync(av_qsv_space * space, av_qsv_context * qsv) ++{ ++ int ret = -1; ++ int counter = 0; ++ ++ while (1) { ++ for (int i = 0; i < space->sync_num; i++) { ++ if (!(*(space->p_syncp[i]->p_sync)) && ++ 0 == space->p_syncp[i]->in_use ) { ++ if (i > space->sync_num_max_used) ++ space->sync_num_max_used = i; ++ ff_qsv_atomic_inc(&space->p_syncp[i]->in_use); ++ return i; ++ } ++ } ++#if HAVE_THREADS ++ if (++counter >= AV_QSV_REPEAT_NUM_DEFAULT) { ++#endif ++ av_log(NULL, AV_LOG_FATAL, "not enough to have %d sync point(s) allocated\n", ++ space->sync_num); ++ break; ++#if HAVE_THREADS ++ } ++ av_qsv_sleep(5); ++#endif ++ } ++ return ret; ++} ++ ++int av_qsv_get_free_surface(av_qsv_space * space, av_qsv_context * qsv, ++ mfxFrameInfo * info, av_qsv_split part) ++{ ++ int ret = -1; ++ int from = 0; ++ int up = space->surface_num; ++ int counter = 0; ++ ++ while (1) { ++ from = 0; ++ up = space->surface_num; ++ if (part == QSV_PART_LOWER) ++ up /= 2; ++ if (part == QSV_PART_UPPER) ++ from = up / 2; ++ ++ for (int i = from; i < up; i++) { ++ if (0 == space->p_surfaces[i]->Data.Locked) { ++ memcpy(&(space->p_surfaces[i]->Info), info, ++ sizeof(mfxFrameInfo)); ++ if (i > space->surface_num_max_used) ++ space->surface_num_max_used = i; ++ return i; ++ } ++ } ++#if HAVE_THREADS ++ if (++counter >= AV_QSV_REPEAT_NUM_DEFAULT) { ++#endif ++ av_log(NULL, AV_LOG_FATAL, ++ "not enough to have %d surface(s) allocated\n", up); ++ break; ++#if HAVE_THREADS ++ } ++ av_qsv_sleep(5); ++#endif ++ } ++ return ret; ++} ++ ++int ff_qsv_is_surface_in_pipe(mfxFrameSurface1 * p_surface, av_qsv_context * qsv) ++{ ++ int ret = 0; ++ int a, b,i; ++ av_qsv_list *list = 0; ++ av_qsv_stage *stage = 0; ++ ++ if (!p_surface) ++ return ret; ++ if (!qsv->pipes) ++ return ret; ++ ++ for (a = 0; a < av_qsv_list_count(qsv->pipes); a++) { ++ list = av_qsv_list_item(qsv->pipes, a); ++ for (b = 0; b < av_qsv_list_count(list); b++) { ++ stage = av_qsv_list_item(list, b); ++ if (p_surface == stage->out.p_surface) ++ return (stage->type << 16) | 2; ++ if (p_surface == stage->in.p_surface) ++ return (stage->type << 16) | 1; ++ } ++ } ++ return ret; ++} ++ ++int ff_qsv_is_sync_in_pipe(mfxSyncPoint * sync, av_qsv_context * qsv) ++{ ++ int ret = 0; ++ int a, b; ++ av_qsv_list *list = 0; ++ av_qsv_stage *stage = 0; ++ ++ if (!sync) ++ return ret; ++ if (!qsv->pipes) ++ return ret; ++ ++ for (a = 0; a < av_qsv_list_count(qsv->pipes); a++) { ++ list = av_qsv_list_item(qsv->pipes, a); ++ for (b = 0; b < av_qsv_list_count(list); b++) { ++ stage = av_qsv_list_item(list, b); ++ if (sync == stage->out.sync->p_sync) { ++ return 1; ++ } ++ } ++ } ++ return ret; ++} ++ ++av_qsv_stage *av_qsv_stage_init(void) ++{ ++ av_qsv_stage *stage = av_mallocz(sizeof(av_qsv_stage)); ++ return stage; ++} ++ ++void av_qsv_stage_clean(av_qsv_stage ** stage) ++{ ++ if ((*stage)->out.sync) { ++ if ((*stage)->out.sync->p_sync) ++ *(*stage)->out.sync->p_sync = 0; ++ if ((*stage)->out.sync->in_use > 0) ++ ff_qsv_atomic_dec(&(*stage)->out.sync->in_use); ++ (*stage)->out.sync = 0; ++ } ++ if ((*stage)->out.p_surface) { ++ (*stage)->out.p_surface = 0; ++ ++ } ++ if ((*stage)->in.p_surface) { ++ (*stage)->in.p_surface = 0; ++ } ++ ++ av_freep(stage); ++} ++ ++void av_qsv_add_context_usage(av_qsv_context * qsv, int is_threaded) ++{ ++ int is_active = 0; ++#if HAVE_THREADS ++ int mut_ret = 0; ++#endif ++ ++ is_active = ff_qsv_atomic_inc(&qsv->is_context_active); ++ if (is_active == 1) { ++ memset(&qsv->mfx_session, 0, sizeof(mfxSession)); ++ av_qsv_pipe_list_create(&qsv->pipes, is_threaded); ++ ++ qsv->dts_seq = av_qsv_list_init(is_threaded); ++ ++#if HAVE_THREADS ++ if (is_threaded) { ++ qsv->qts_seq_mutex = av_mallocz(sizeof(pthread_mutex_t)); ++ if (qsv->qts_seq_mutex){ ++ mut_ret = pthread_mutex_init(qsv->qts_seq_mutex, NULL); ++ if(mut_ret) ++ av_log(NULL, AV_LOG_ERROR, "pthread_mutex_init issue[%d] at %s\n",mut_ret,__FUNCTION__); ++ } ++ ++ } else ++#endif ++ qsv->qts_seq_mutex = 0; ++ } ++} ++ ++int av_qsv_context_clean(av_qsv_context * qsv) ++{ ++ int is_active = 0; ++ mfxStatus sts = MFX_ERR_NONE; ++#if HAVE_THREADS ++ int mut_ret = 0; ++#endif ++ ++ is_active = ff_qsv_atomic_dec(&qsv->is_context_active); ++ ++ // spaces would have to be cleaned on the own, ++ // here we care about the rest, common stuff ++ if (is_active == 0) { ++ ++ if (qsv->dts_seq) { ++ while (av_qsv_list_count(qsv->dts_seq)) ++ av_qsv_dts_pop(qsv); ++ ++ av_qsv_list_close(&qsv->dts_seq); ++ } ++#if HAVE_THREADS ++ if (qsv->qts_seq_mutex) { ++ mut_ret = pthread_mutex_destroy(qsv->qts_seq_mutex); ++ if(mut_ret) ++ av_log(NULL, AV_LOG_ERROR, "pthread_mutex_destroy issue[%d] at %s\n", mut_ret,__FUNCTION__); ++#endif ++ qsv->qts_seq_mutex = 0; ++#if HAVE_THREADS ++ } ++#endif ++ ++ if (qsv->pipes) ++ av_qsv_pipe_list_clean(&qsv->pipes); ++ ++ if (qsv->mfx_session) { ++ sts = MFXClose(qsv->mfx_session); ++ AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts); ++ qsv->mfx_session = 0; ++ } ++ } ++ return 0; ++} ++ ++void av_qsv_pipe_list_create(av_qsv_list ** list, int is_threaded) ++{ ++ if (!*list) ++ *list = av_qsv_list_init(is_threaded); ++} ++ ++void av_qsv_pipe_list_clean(av_qsv_list ** list) ++{ ++ av_qsv_list *stage; ++ int i = 0; ++ if (*list) { ++ for (i = av_qsv_list_count(*list); i > 0; i--) { ++ stage = av_qsv_list_item(*list, i - 1); ++ av_qsv_flush_stages(*list, &stage); ++ } ++ av_qsv_list_close(list); ++ } ++} ++ ++void av_qsv_add_stagee(av_qsv_list ** list, av_qsv_stage * stage, int is_threaded) ++{ ++ if (!*list) ++ *list = av_qsv_list_init(is_threaded); ++ av_qsv_list_add(*list, stage); ++} ++ ++av_qsv_stage *av_qsv_get_last_stage(av_qsv_list * list) ++{ ++ av_qsv_stage *stage = 0; ++ int size = 0; ++ ++ av_qsv_list_lock(list); ++ size = av_qsv_list_count(list); ++ if (size > 0) ++ stage = av_qsv_list_item(list, size - 1); ++ av_qsv_list_unlock(list); ++ ++ return stage; ++} ++ ++void av_qsv_flush_stages(av_qsv_list * list, av_qsv_list ** item) ++{ ++ int i = 0; ++ int x = 0; ++ av_qsv_stage *stage = 0; ++ av_qsv_list *to_remove_list = 0; ++ av_qsv_list *to_remove_atom_list = 0; ++ av_qsv_list *to_remove_atom = 0; ++ ++ for (i = 0; i < av_qsv_list_count(*item); i++) { ++ stage = av_qsv_list_item(*item, i); ++ if(stage->pending){ ++ if(!to_remove_list) ++ to_remove_list = av_qsv_list_init(0); ++ av_qsv_list_add(to_remove_list, stage->pending); ++ } ++ av_qsv_stage_clean(&stage); ++ // should actually remove from the list but ok... ++ } ++ av_qsv_list_rem(list, *item); ++ av_qsv_list_close(item); ++ ++ if(to_remove_list){ ++ for (i = av_qsv_list_count(to_remove_list); i > 0; i--){ ++ to_remove_atom_list = av_qsv_list_item(to_remove_list, i-1); ++ for (x = av_qsv_list_count(to_remove_atom_list); x > 0; x--){ ++ to_remove_atom = av_qsv_list_item(to_remove_atom_list, x-1); ++ av_qsv_flush_stages(list,&to_remove_atom); ++ } ++ } ++ av_qsv_list_close(&to_remove_list); ++ } ++} ++ ++av_qsv_list *av_qsv_pipe_by_stage(av_qsv_list * list, av_qsv_stage * stage) ++{ ++ av_qsv_list *item = 0; ++ av_qsv_stage *cur_stage = 0; ++ int i = 0; ++ int a = 0; ++ for (i = 0; i < av_qsv_list_count(list); i++) { ++ item = av_qsv_list_item(list, i); ++ for (a = 0; a < av_qsv_list_count(item); a++) { ++ cur_stage = av_qsv_list_item(item, a); ++ if (cur_stage == stage) ++ return item; ++ } ++ } ++ return 0; ++} ++ ++// no duplicate of the same value, if end == 0 : working over full length ++void av_qsv_dts_ordered_insert(av_qsv_context * qsv, int start, int end, ++ int64_t dts, int iter) ++{ ++ av_qsv_dts *cur_dts = 0; ++ av_qsv_dts *new_dts = 0; ++ int i = 0; ++#if HAVE_THREADS ++ int mut_ret = 0; ++#endif ++ ++ ++#if HAVE_THREADS ++ if (iter == 0 && qsv->qts_seq_mutex){ ++ mut_ret = pthread_mutex_lock(qsv->qts_seq_mutex); ++ if(mut_ret) ++ av_log(NULL, AV_LOG_ERROR, "pthread_mutex_lock issue[%d] at %s\n",mut_ret, __FUNCTION__); ++ } ++#endif ++ ++ if (end == 0) ++ end = av_qsv_list_count(qsv->dts_seq); ++ ++ if (end <= start) { ++ new_dts = av_mallocz(sizeof(av_qsv_dts)); ++ if( new_dts ) { ++ new_dts->dts = dts; ++ av_qsv_list_add(qsv->dts_seq, new_dts); ++ } ++ } else ++ for (i = end; i > start; i--) { ++ cur_dts = av_qsv_list_item(qsv->dts_seq, i - 1); ++ if (cur_dts->dts < dts) { ++ new_dts = av_mallocz(sizeof(av_qsv_dts)); ++ if( new_dts ) { ++ new_dts->dts = dts; ++ av_qsv_list_insert(qsv->dts_seq, i, new_dts); ++ } ++ break; ++ } else if (cur_dts->dts == dts) ++ break; ++ } ++#if HAVE_THREADS ++ if (iter == 0 && qsv->qts_seq_mutex){ ++ mut_ret = pthread_mutex_unlock(qsv->qts_seq_mutex); ++ if(mut_ret) ++ av_log(NULL, AV_LOG_ERROR, "pthread_mutex_unlock issue[%d] at %s\n",mut_ret, __FUNCTION__); ++ } ++#endif ++} ++ ++void av_qsv_dts_pop(av_qsv_context * qsv) ++{ ++ av_qsv_dts *item = 0; ++#if HAVE_THREADS ++ int mut_ret = 0; ++#endif ++ ++#if HAVE_THREADS ++ if (qsv && qsv->qts_seq_mutex){ ++ mut_ret = pthread_mutex_lock(qsv->qts_seq_mutex); ++ if(mut_ret) ++ av_log(NULL, AV_LOG_ERROR, "pthread_mutex_lock issue[%d] at %s\n",mut_ret, __FUNCTION__); ++ } ++#endif ++ ++ if (av_qsv_list_count(qsv->dts_seq)) { ++ item = av_qsv_list_item(qsv->dts_seq, 0); ++ av_qsv_list_rem(qsv->dts_seq, item); ++ av_free(item); ++ } ++#if HAVE_THREADS ++ if (qsv && qsv->qts_seq_mutex){ ++ mut_ret = pthread_mutex_unlock(qsv->qts_seq_mutex); ++ if(mut_ret) ++ av_log(NULL, AV_LOG_ERROR, "pthread_mutex_lock issue[%d] at %s\n",mut_ret, __FUNCTION__); ++ } ++#endif ++} ++ ++ ++av_qsv_list *av_qsv_list_init(int is_threaded) ++{ ++ av_qsv_list *l; ++#if HAVE_THREADS ++ int mut_ret; ++#endif ++ ++ l = av_mallocz(sizeof(av_qsv_list)); ++ if (!l) ++ return 0; ++ l->items = av_mallocz(AV_QSV_JOB_SIZE_DEFAULT * sizeof(void *)); ++ if (!l->items) ++ return 0; ++ l->items_alloc = AV_QSV_JOB_SIZE_DEFAULT; ++ ++#if HAVE_THREADS ++ if (is_threaded) { ++ l->mutex = av_mallocz(sizeof(pthread_mutex_t)); ++ if (l->mutex){ ++ mut_ret = pthread_mutexattr_init(&l->mta); ++ if( mut_ret ) ++ av_log(NULL, AV_LOG_ERROR, "pthread_mutexattr_init issue[%d] at %s\n",mut_ret, __FUNCTION__); ++ mut_ret = pthread_mutexattr_settype(&l->mta, PTHREAD_MUTEX_RECURSIVE /*PTHREAD_MUTEX_ERRORCHECK*/); ++ if( mut_ret ) ++ av_log(NULL, AV_LOG_ERROR, "pthread_mutexattr_settype issue[%d] at %s\n",mut_ret, __FUNCTION__); ++ mut_ret = pthread_mutex_init(l->mutex, &l->mta); ++ if( mut_ret ) ++ av_log(NULL, AV_LOG_ERROR, "pthread_mutex_init issue[%d] at %s\n",mut_ret, __FUNCTION__); ++ } ++ } else ++#endif ++ l->mutex = 0; ++ return l; ++} ++ ++int av_qsv_list_count(av_qsv_list * l) ++{ ++ int count; ++ ++ av_qsv_list_lock(l); ++ count = l->items_count; ++ av_qsv_list_unlock(l); ++ return count; ++} ++ ++int av_qsv_list_add(av_qsv_list * l, void *p) ++{ ++ int pos = -1; ++ ++ if (!p) { ++ return pos; ++ } ++ ++ av_qsv_list_lock(l); ++ ++ if (l->items_count == l->items_alloc) { ++ /* We need a bigger boat */ ++ l->items_alloc += AV_QSV_JOB_SIZE_DEFAULT; ++ l->items = av_realloc(l->items, l->items_alloc * sizeof(void *)); ++ } ++ ++ l->items[l->items_count] = p; ++ pos = (l->items_count); ++ l->items_count++; ++ ++ av_qsv_list_unlock(l); ++ ++ return pos; ++} ++ ++void av_qsv_list_rem(av_qsv_list * l, void *p) ++{ ++ int i; ++ ++ av_qsv_list_lock(l); ++ ++ /* Find the item in the list */ ++ for (i = 0; i < l->items_count; i++) { ++ if (l->items[i] == p) { ++ /* Shift all items after it sizeof( void * ) bytes earlier */ ++ memmove(&l->items[i], &l->items[i + 1], ++ (l->items_count - i - 1) * sizeof(void *)); ++ ++ l->items_count--; ++ break; ++ } ++ } ++ ++ av_qsv_list_unlock(l); ++} ++ ++void *av_qsv_list_item(av_qsv_list * l, int i) ++{ ++ void *ret = NULL; ++ ++ if (i < 0) ++ return NULL; ++ ++ av_qsv_list_lock(l); ++ if( i < l->items_count) ++ ret = l->items[i]; ++ av_qsv_list_unlock(l); ++ return ret; ++} ++ ++void av_qsv_list_insert(av_qsv_list * l, int pos, void *p) ++{ ++ ++ if (!p) ++ return; ++ ++ av_qsv_list_lock(l); ++ ++ if (l->items_count == l->items_alloc) { ++ l->items_alloc += AV_QSV_JOB_SIZE_DEFAULT; ++ l->items = av_realloc(l->items, l->items_alloc * sizeof(void *)); ++ } ++ ++ if (l->items_count != pos) { ++ memmove(&l->items[pos + 1], &l->items[pos], ++ (l->items_count - pos) * sizeof(void *)); ++ } ++ ++ l->items[pos] = p; ++ l->items_count--; ++ ++ av_qsv_list_unlock(l); ++} ++ ++void av_qsv_list_close(av_qsv_list ** _l) ++{ ++ av_qsv_list *l = *_l; ++#if HAVE_THREADS ++ int mut_ret; ++#endif ++ ++ av_qsv_list_lock(l); ++ ++ av_free(l->items); ++ ++#if HAVE_THREADS ++ if (l->mutex){ ++ mut_ret = pthread_mutex_unlock(l->mutex); ++ if( mut_ret ) ++ av_log(NULL, AV_LOG_ERROR, "pthread_mutex_unlock issue[%d] at %s\n",mut_ret, __FUNCTION__); ++ mut_ret = pthread_mutex_destroy(&l->mutex); ++ mut_ret = pthread_mutexattr_destroy(&l->mta); ++ } ++#endif ++ av_freep(_l); ++} ++ ++int av_qsv_list_lock(av_qsv_list *l){ ++ int ret = 0; ++#if HAVE_THREADS ++ if (l->mutex){ ++ ret = pthread_mutex_lock(l->mutex); ++ if( ret ) ++ av_log(NULL, AV_LOG_ERROR, "pthread_mutex_lock issue[%d] at %s\n",ret, __FUNCTION__); ++ } ++#endif ++ return ret; ++} ++ ++int av_qsv_list_unlock(av_qsv_list *l){ ++ int ret = 0; ++#if HAVE_THREADS ++ if (l->mutex){ ++ ret = pthread_mutex_unlock(l->mutex); ++ if( ret ) ++ av_log(NULL, AV_LOG_ERROR, "pthread_mutex_unlock issue[%d] at %s\n",ret, __FUNCTION__); ++ } ++#endif ++ return ret; ++} ++ ++int av_is_qsv_available(mfxIMPL impl, mfxVersion * ver) ++{ ++ mfxStatus sts = MFX_ERR_NONE; ++ mfxSession mfx_session; ++ ++ memset(&mfx_session, 0, sizeof(mfxSession)); ++ sts = MFXInit(impl, ver, &mfx_session); ++ if (sts >= 0) ++ MFXClose(mfx_session); ++ return sts; ++} ++ ++void av_qsv_wait_on_sync(av_qsv_context *qsv, av_qsv_stage *stage) ++{ ++ int iter = 0; ++ mfxStatus sts = MFX_ERR_NONE; ++ if( stage ) ++ if(*stage->out.sync->p_sync){ ++ while(1){ ++ iter++; ++ sts = MFXVideoCORE_SyncOperation(qsv->mfx_session,*stage->out.sync->p_sync, AV_QSV_SYNC_TIME_DEFAULT); ++ if(MFX_WRN_IN_EXECUTION == sts){ ++ ++ if(iter>20) ++ AV_QSV_DEBUG_ASSERT(1, "Sync failed"); ++ ++ av_qsv_sleep(10); ++ continue; ++ } ++ AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts); ++ break; ++ } ++ } ++} +\ No newline at end of file +diff -Naur ../../libav-v9.6/libavcodec/qsv.h ./libavcodec/qsv.h +--- ../../libav-v9.6/libavcodec/qsv.h 1970-01-01 01:00:00.000000000 +0100 ++++ ./libavcodec/qsv.h 2013-08-19 21:32:01.709244686 +0200 +@@ -0,0 +1,494 @@ ++/* ********************************************************************* *\ ++ ++Copyright (C) 2013 Intel Corporation. All rights reserved. ++ ++Redistribution and use in source and binary forms, with or without ++modification, are permitted provided that the following conditions are met: ++- Redistributions of source code must retain the above copyright notice, ++this list of conditions and the following disclaimer. ++- Redistributions in binary form must reproduce the above copyright notice, ++this list of conditions and the following disclaimer in the documentation ++and/or other materials provided with the distribution. ++- Neither the name of Intel Corporation nor the names of its contributors ++may be used to endorse or promote products derived from this software ++without specific prior written permission. ++ ++THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION "AS IS" AND ANY EXPRESS OR ++IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, ++INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ ++\* ********************************************************************* */ ++ ++#ifndef AVCODEC_QSV_H ++#define AVCODEC_QSV_H ++ ++/** ++ * @file ++ * @ingroup lavc_codec_hwaccel_qsv ++ * Common header for QSV/MediaSDK acceleration ++ */ ++ ++/** ++ * @defgroup lavc_codec_hwaccel_qsv QSV/MediaSDK based Decode/Encode and VPP ++ * @ingroup lavc_codec_hwaccel ++ * ++ * As Intel Quick Sync Video (QSV) can decode/preprocess/encode with HW ++ * acceleration. ++ * ++ * Supported features: ++ * - access: ++ * - format AV_PIX_FMT_QSV_H264, AVCodec decoder based implementation ++ * - name "h264_qsv", avcodec_find_decoder_by_name( "h264_qsv") ++ * - IO Pattern: ++ * - Opaque memory: MFX_IOPATTERN_OUT_OPAQUE_MEMORY // Video memory is ++ * MFX_IMPL_HARDWARE or MFX_IMPL_AUTO and runtime support, ++ * otherwise: System Memory ++ * - System memory: MFX_IOPATTERN_OUT_SYSTEM_MEMORY ++ * - Allocators: ++ * - default allocator for System memory: MFX_MEMTYPE_SYSTEM_MEMORY ++ * - details: ++ * implementation as "per frame" ++ * ++ * TODO list: ++ * - access: ++ * - format AV_PIX_FMT_QSV_MPEG2 ++ * - format AV_PIX_FMT_QSV_VC1 ++ * - format AV_PIX_FMT_QSV, see "details" below ++ * - IO Pattern: ++ * - VIDEO_MEMORY // MFX_IOPATTERN_OUT_VIDEO_MEMORY ++ * - Allocators: ++ * - Video memory: MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET / ++ * MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET ++ * - details: ++ * "per slice" support: AV_PIX_FMT_QSV with AVHWAccel based implementation ++ * ++ * Note av_qsv_config struct required to fill in via ++ * AVCodecContext.hwaccel_context ++ * ++ * As per frame, note AVFrame.data[2] (qsv_atom) used for frame atom id, ++ * data/linesize should be used together with SYSTEM_MEMORY and tested ++ * ++ * Note: Compilation would require: ++ * - Intel MediaSDK headers, Full SDK is avaialble from the original web site: ++ * http://software.intel.com/en-us/vcsource/tools/media-SDK ++ * Will be referenced as msdk/*.h (mfxdefs.h, mfxstructures.h, ... ) ++ * and ++ * - Final application has to link against Intel MediaSDK dispatcher, available ++ * at MediaSDK as well ++ * ++ * Target OS: as per available dispatcher and driver support ++ * ++ * Implementation details: ++ * Provided struct av_qsv_context contain several struct av_qsv_space(s) for decode, ++ * VPP and encode. ++ * av_qsv_space just contain needed environment for the appropriate action. ++ * Based on this - pipeline (see pipes) will be build to pass details such as ++ * mfxFrameSurface1* and mfxSyncPoint* from one action to the next. ++ * ++ * Resources re-usage (av_qsv_flush_stages): ++ * av_qsv_context *qsv = (av_qsv_context *)video_codec_ctx->priv_data; ++ * av_qsv_list *pipe = (av_qsv_list *)video_frame->data[2]; ++ * av_qsv_flush_stages( qsv->pipes, &pipe ); ++ * ++ * DTS re-usage: ++ * av_qsv_dts_pop(qsv); ++ * ++ * for video,DX9/11 memory it has to be Unlock'ed as well ++ * ++ * Implementation is thread aware and uses synchronization point(s) from MediaSDK ++ * as per configuration. ++ * ++ * For the details of MediaSDK usage and options available - please refer to the ++ * available documentation at MediaSDK. ++ * ++ * Feature set used from MSDK is defined by AV_QSV_MSDK_VERSION_MAJOR and ++ * AV_QSV_MSDK_VERSION_MINOR ++ * ++ * @{ ++ */ ++ ++#include <stdint.h> ++#include <string.h> ++#include "msdk/mfxvideo.h" ++#include "libavutil/mem.h" ++#include "libavutil/time.h" ++ ++#ifdef HAVE_AV_CONFIG_H ++#include "config.h" ++#endif ++ ++#if HAVE_THREADS ++#if defined (__GNUC__) ++#include <pthread.h> ++#define ff_qsv_atomic_inc(ptr) __sync_add_and_fetch(ptr,1) ++#define ff_qsv_atomic_dec(ptr) __sync_sub_and_fetch (ptr,1) ++#elif HAVE_WINDOWS_H // MSVC case ++#include <windows.h> ++#if HAVE_PTHREADS ++#include <pthread.h> ++#elif HAVE_W32THREADS ++#include "w32pthreads.h" ++#endif ++#define ff_qsv_atomic_inc(ptr) InterlockedIncrement(ptr) ++#define ff_qsv_atomic_dec(ptr) InterlockedDecrement (ptr) ++#else ++// targeting only for MinGW or MSVC ++#endif ++ ++#else ++#define ff_qsv_atomic_inc(ptr) ((*ptr)++) ++#define ff_qsv_atomic_dec(ptr) ((*ptr)--) ++#endif ++ ++ ++// sleep is defined in milliseconds ++#define av_qsv_sleep(x) av_usleep((x)*1000) ++ ++#define AV_QSV_ZERO_MEMORY(VAR) {memset(&VAR, 0, sizeof(VAR));} ++#define AV_QSV_ALIGN32(X) (((mfxU32)((X)+31)) & (~ (mfxU32)31)) ++#define AV_QSV_ALIGN16(value) (((value + 15) >> 4) << 4) ++#ifndef AV_QSV_PRINT_RET_MSG ++#define AV_QSV_PRINT_RET_MSG(ERR) { av_log(NULL, AV_LOG_FATAL,"Error code %d,\t%s\t%d\n", ERR, __FUNCTION__, __LINE__); } ++#endif ++ ++#ifndef AV_QSV_DEBUG_ASSERT ++#define AV_QSV_DEBUG_ASSERT(x,y) {if ((x)) {av_log(NULL, AV_LOG_FATAL,"\nASSERT: %s\n",y);};} ++#endif ++ ++#define AV_QSV_CHECK_RESULT(P, X, ERR) {if ((X) > (P)) {AV_QSV_PRINT_RET_MSG(ERR); return ERR;}} ++#define AV_QSV_CHECK_POINTER(P, ERR) {if (!(P)) {AV_QSV_PRINT_RET_MSG(ERR); return ERR;}} ++#define AV_QSV_IGNORE_MFX_STS(P, X) {if ((X) == (P)) {P = MFX_ERR_NONE;}} ++ ++#define AV_QSV_ID_BUFFER MFX_MAKEFOURCC('B','U','F','F') ++#define AV_QSV_ID_FRAME MFX_MAKEFOURCC('F','R','M','E') ++ ++#define AV_QSV_SURFACE_NUM 80 ++#define AV_QSV_SYNC_NUM AV_QSV_SURFACE_NUM*3/4 ++#define AV_QSV_BUF_SIZE_DEFAULT 4096*2160*10 ++#define AV_QSV_JOB_SIZE_DEFAULT 10 ++#define AV_QSV_SYNC_TIME_DEFAULT 10000 ++// see av_qsv_get_free_sync, av_qsv_get_free_surface , 100 if usleep(10*1000)(10ms) == 1 sec ++#define AV_QSV_REPEAT_NUM_DEFAULT 100 ++#define AV_QSV_ASYNC_DEPTH_DEFAULT 4 ++ ++// version of MSDK/QSV API currently used ++#define AV_QSV_MSDK_VERSION_MAJOR 1 ++#define AV_QSV_MSDK_VERSION_MINOR 3 ++ ++typedef enum AV_QSV_STAGE_TYPE { ++ ++#define AV_QSV_DECODE_MASK 0x001 ++ AV_QSV_DECODE = 0x001, ++ ++#define AV_QSV_VPP_MASK 0x0F0 ++ // "Mandatory VPP filter" , might be with "Hint-based VPP filters" ++ AV_QSV_VPP_DEFAULT = 0x010, ++ // "User Modules" etc ++ AV_QSV_VPP_USER = 0x020, ++ ++#define av_QSV_ENCODE_MASK 0x100 ++ AV_QSV_ENCODE = 0x100 ++#define AV_QSV_ANY_MASK 0xFFF ++} AV_QSV_STAGE_TYPE; ++ ++ ++typedef struct av_qsv_list { ++ // practically pthread_mutex_t ++ void *mutex; ++#if HAVE_THREADS ++ pthread_mutexattr_t mta; ++#endif ++ ++ void **items; ++ int items_alloc; ++ ++ int items_count; ++} av_qsv_list; ++ ++typedef struct av_qsv_sync { ++ mfxSyncPoint* p_sync; ++ int in_use; ++} av_qsv_sync; ++ ++typedef struct av_qsv_stage { ++ AV_QSV_STAGE_TYPE type; ++ struct { ++ mfxBitstream *p_bs; ++ mfxFrameSurface1 *p_surface; ++ } in; ++ struct { ++ mfxBitstream *p_bs; ++ mfxFrameSurface1 *p_surface; ++ av_qsv_sync *sync; ++ } out; ++ av_qsv_list *pending; ++} av_qsv_stage; ++ ++typedef struct av_qsv_task { ++ mfxBitstream *bs; ++ av_qsv_stage *stage; ++} av_qsv_task; ++ ++ ++typedef struct av_qsv_space { ++ ++ uint8_t is_init_done; ++ ++ AV_QSV_STAGE_TYPE type; ++ ++ mfxVideoParam m_mfxVideoParam; ++ ++ mfxFrameAllocResponse response; ++ mfxFrameAllocRequest request[2]; // [0] - in, [1] - out, if needed ++ ++ mfxExtOpaqueSurfaceAlloc ext_opaque_alloc; ++ mfxExtBuffer **p_ext_params; ++ uint16_t p_ext_param_num; ++ ++ uint16_t surface_num_max_used; ++ uint16_t surface_num; ++ mfxFrameSurface1 *p_surfaces[AV_QSV_SURFACE_NUM]; ++ ++ uint16_t sync_num_max_used; ++ uint16_t sync_num; ++ av_qsv_sync *p_syncp[AV_QSV_SYNC_NUM]; ++ ++ mfxBitstream bs; ++ uint8_t *p_buf; ++ size_t p_buf_max_size; ++ ++ // only for encode and tasks ++ av_qsv_list *tasks; ++ ++ av_qsv_list *pending; ++ ++ // storage for allocations/mfxMemId* ++ mfxMemId *mids; ++} av_qsv_space; ++ ++typedef struct av_qsv_context { ++ volatile int is_context_active; ++ ++ mfxIMPL impl; ++ mfxSession mfx_session; ++ mfxVersion ver; ++ ++ // decode ++ av_qsv_space *dec_space; ++ // encode ++ av_qsv_space *enc_space; ++ // vpp ++ av_qsv_list *vpp_space; ++ ++ av_qsv_list *pipes; ++ ++ // MediaSDK starting from API version 1.6 includes DecodeTimeStamp ++ // in addition to TimeStamp ++ // see also AV_QSV_MSDK_VERSION_MINOR , AV_QSV_MSDK_VERSION_MAJOR ++ av_qsv_list *dts_seq; ++ ++ // practically pthread_mutex_t ++ void *qts_seq_mutex; ++ ++ int is_anex; ++ ++ void *qsv_config; ++ ++} av_qsv_context; ++ ++typedef enum { ++ QSV_PART_ANY = 0, ++ QSV_PART_LOWER, ++ QSV_PART_UPPER ++} av_qsv_split; ++ ++typedef struct { ++ int64_t dts; ++} av_qsv_dts; ++ ++typedef struct av_qsv_alloc_frame { ++ mfxU32 id; ++ mfxFrameInfo info; ++} av_qsv_alloc_frame; ++ ++typedef struct av_qsv_alloc_buffer { ++ mfxU32 id; ++ mfxU32 nbytes; ++ mfxU16 type; ++} av_qsv_alloc_buffer; ++ ++typedef struct av_qsv_allocators_space { ++ av_qsv_space *space; ++ mfxFrameAllocator frame_alloc; ++ mfxBufferAllocator buffer_alloc; ++} av_qsv_allocators_space; ++ ++typedef struct av_qsv_config { ++ /** ++ * Set asynch depth of processing with QSV ++ * Format: 0 and more ++ * ++ * - encoding: Set by user. ++ * - decoding: Set by user. ++ */ ++ int async_depth; ++ ++ /** ++ * Range of numbers that indicate trade-offs between quality and speed. ++ * Format: from 1/MFX_TARGETUSAGE_BEST_QUALITY to 7/MFX_TARGETUSAGE_BEST_SPEED inclusive ++ * ++ * - encoding: Set by user. ++ * - decoding: unused ++ */ ++ int target_usage; ++ ++ /** ++ * Number of reference frames; if NumRefFrame = 0, this parameter is not specified. ++ * Format: 0 and more ++ * ++ * - encoding: Set by user. ++ * - decoding: unused ++ */ ++ int num_ref_frame; ++ ++ /** ++ * Distance between I- or P- key frames; if it is zero, the GOP structure is unspecified. ++ * Note: If GopRefDist = 1, there are no B-frames used. ++ * ++ * - encoding: Set by user. ++ * - decoding: unused ++ */ ++ int gop_ref_dist; ++ ++ /** ++ * Number of pictures within the current GOP (Group of Pictures); if GopPicSize=0, ++ * then the GOP size is unspecified. If GopPicSize=1, only I-frames are used. ++ * ++ * - encoding: Set by user. ++ * - decoding: unused ++ */ ++ int gop_pic_size; ++ ++ /** ++ * Set type of surfaces used with QSV ++ * Format: "IOPattern enum" of Media SDK ++ * ++ * - encoding: Set by user. ++ * - decoding: Set by user. ++ */ ++ int io_pattern; ++ ++ /** ++ * Set amount of additional surfaces might be needed ++ * Format: ammount of additional buffers(surfaces+syncs) ++ * to allocate in advance ++ * ++ * - encoding: Set by user. ++ * - decoding: Set by user. ++ */ ++ int additional_buffers; ++ ++ /** ++ * If pipeline should be sync. ++ * Format: wait time in milliseconds, ++ * AV_QSV_SYNC_TIME_DEFAULT/10000 might be a good value ++ * ++ * - encoding: Set by user. ++ * - decoding: Set by user. ++ */ ++ int sync_need; ++ ++ /** ++ * Type of implementation needed ++ * ++ * - encoding: Set by user. ++ * - decoding: Set by user. ++ */ ++ int impl_requested; ++ ++ /** ++ * if QSV usage is multithreaded. ++ * Format: Yes/No, 1/0 ++ * ++ * - encoding: Set by user. ++ * - decoding: Set by user. ++ */ ++ int usage_threaded; ++ ++ /** ++ * if QSV use an external allocation (valid per session/mfxSession) ++ * Format: pointer to allocators, if default: 0 ++ * ++ * note that: ++ * System Memory: can be used without provided and external allocator, ++ * meaning MediaSDK will use an internal one ++ * Video Memory: in this case - we must provide an external allocator ++ * Also, Media SDK session doesn't require external allocator if the application ++ * uses opaque memory ++ * ++ * Calls SetFrameAllocator/SetBufferAllocator ++ * (MFXVideoCORE_SetFrameAllocator/MFXVideoCORE_SetBufferAllocator) ++ * are to pass allocators to Media SDK ++ * ++ * - encoding: Set by user. ++ * - decoding: Set by user. ++ */ ++ av_qsv_allocators_space *allocators; ++ ++} av_qsv_config; ++ ++#define ANEX_UNKNOWN 0 ++#define ANEX_PREFIX 1 ++#define ANEX_NO_PREFIX 2 ++ ++static const uint8_t ff_prefix_code[] = { 0x00, 0x00, 0x00, 0x01 }; ++ ++int av_qsv_get_free_sync(av_qsv_space *, av_qsv_context *); ++int av_qsv_get_free_surface(av_qsv_space *, av_qsv_context *, mfxFrameInfo *, ++ av_qsv_split); ++int av_qsv_get_free_encode_task(av_qsv_list *); ++ ++int av_is_qsv_available(mfxIMPL, mfxVersion *); ++void av_qsv_wait_on_sync(av_qsv_context *, av_qsv_stage *); ++ ++void av_qsv_add_context_usage(av_qsv_context *, int); ++ ++void av_qsv_pipe_list_create(av_qsv_list **, int); ++void av_qsv_pipe_list_clean(av_qsv_list **); ++ ++void av_qsv_add_stagee(av_qsv_list **, av_qsv_stage *, int); ++av_qsv_stage *av_qsv_get_last_stage(av_qsv_list *); ++av_qsv_list *av_qsv_pipe_by_stage(av_qsv_list *, av_qsv_stage *); ++void av_qsv_flush_stages(av_qsv_list *, av_qsv_list **); ++ ++void av_qsv_dts_ordered_insert(av_qsv_context *, int, int, int64_t, int); ++void av_qsv_dts_pop(av_qsv_context *); ++ ++av_qsv_stage *av_qsv_stage_init(void); ++void av_qsv_stage_clean(av_qsv_stage **); ++int av_qsv_context_clean(av_qsv_context *); ++ ++int ff_qsv_is_sync_in_pipe(mfxSyncPoint *, av_qsv_context *); ++int ff_qsv_is_surface_in_pipe(mfxFrameSurface1 *, av_qsv_context *); ++ ++av_qsv_list *av_qsv_list_init(int); ++int av_qsv_list_lock(av_qsv_list *); ++int av_qsv_list_unlock(av_qsv_list *); ++int av_qsv_list_add(av_qsv_list *, void *); ++void av_qsv_list_rem(av_qsv_list *, void *); ++void av_qsv_list_insert(av_qsv_list *, int, void *); ++void av_qsv_list_close(av_qsv_list **); ++ ++int av_qsv_list_count(av_qsv_list *); ++void *av_qsv_list_item(av_qsv_list *, int); ++ ++/* @} */ ++ ++#endif //AVCODEC_QSV_H +diff -Naur ../../libav-v9.6/libavcodec/qsv_h264.c ./libavcodec/qsv_h264.c +--- ../../libav-v9.6/libavcodec/qsv_h264.c 1970-01-01 01:00:00.000000000 +0100 ++++ ./libavcodec/qsv_h264.c 2013-08-19 21:32:01.705244194 +0200 +@@ -0,0 +1,974 @@ ++/* ********************************************************************* *\ ++ ++Copyright (C) 2013 Intel Corporation. All rights reserved. ++ ++Redistribution and use in source and binary forms, with or without ++modification, are permitted provided that the following conditions are met: ++- Redistributions of source code must retain the above copyright notice, ++this list of conditions and the following disclaimer. ++- Redistributions in binary form must reproduce the above copyright notice, ++this list of conditions and the following disclaimer in the documentation ++and/or other materials provided with the distribution. ++- Neither the name of Intel Corporation nor the names of its contributors ++may be used to endorse or promote products derived from this software ++without specific prior written permission. ++ ++THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION "AS IS" AND ANY EXPRESS OR ++IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, ++INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ ++\* ********************************************************************* */ ++ ++#include "h264.h" ++#include "h264data.h" ++#include "qsv_h264.h" ++ ++static av_qsv_config av_qsv_default_config = { ++ .async_depth = AV_QSV_ASYNC_DEPTH_DEFAULT, ++ .target_usage = MFX_TARGETUSAGE_BALANCED, ++ .num_ref_frame = 0, ++ .gop_ref_dist = 0, ++ .gop_pic_size = 0, ++ .io_pattern = MFX_IOPATTERN_OUT_OPAQUE_MEMORY, ++ .additional_buffers = 0, ++ .sync_need = 0, ++ .impl_requested = MFX_IMPL_HARDWARE, ++ .usage_threaded = 0, ++ .allocators = 0, ++}; ++ ++static av_qsv_allocators_space av_qsv_default_system_allocators = { ++ // fill to access mids ++ .space = 0, ++ ++ .frame_alloc = { ++ .pthis = &av_qsv_default_system_allocators, ++ .Alloc = ff_qsv_mem_frame_alloc, ++ .Lock = ff_qsv_mem_frame_lock, ++ .Unlock = ff_qsv_mem_frame_unlock, ++ .GetHDL = ff_qsv_mem_frame_getHDL, ++ .Free = ff_qsv_mem_frame_free, ++ }, ++ .buffer_alloc = { ++ .pthis = &av_qsv_default_system_allocators, ++ .Alloc = ff_qsv_mem_buffer_alloc, ++ .Lock = ff_qsv_mem_buffer_lock, ++ .Unlock = ff_qsv_mem_buffer_unlock, ++ .Free = ff_qsv_mem_buffer_free, ++ }, ++}; ++ ++static const uint8_t ff_slice_code[] = { 0x00, 0x00, 0x01, 0x65 }; ++ ++int ff_qsv_nal_find_start_code(uint8_t * pb, size_t size) ++{ ++ if ((int) size < 4) ++ return 0; ++ ++ while ((4 <= size) && ((0 != pb[0]) || (0 != pb[1]) || (0 != pb[2]) || (1 != pb[3]))) { ++ pb += 1; ++ size -= 1; ++ } ++ ++ if (4 <= size) ++ return 1; ++ ++ return 0; ++} ++ ++int ff_qsv_dec_init_clean(AVCodecContext *avctx) ++{ ++ mfxStatus sts = MFX_ERR_NONE; ++ av_qsv_context *qsv = avctx->priv_data; ++ av_qsv_space *qsv_decode = qsv->dec_space; ++ av_qsv_context_clean(qsv); ++ av_freep(&avctx->priv_data); ++} ++int ff_qsv_dec_init(AVCodecContext * avctx) ++{ ++ int ret = 0; ++ mfxStatus sts = MFX_ERR_NONE; ++ size_t current_offset = 6; ++ int header_size = 0; ++ unsigned char *current_position; ++ size_t current_size; ++ ++ av_qsv_context *qsv = avctx->priv_data; ++ av_qsv_space *qsv_decode = qsv->dec_space; ++ av_qsv_config *qsv_config_context = avctx->hwaccel_context; ++ ++ qsv->impl = qsv_config_context->impl_requested; ++ ++ memset(&qsv->mfx_session, 0, sizeof(mfxSession)); ++ qsv->ver.Major = AV_QSV_MSDK_VERSION_MAJOR; ++ qsv->ver.Minor = AV_QSV_MSDK_VERSION_MINOR; ++ ++ sts = MFXInit(qsv->impl, &qsv->ver, &qsv->mfx_session); ++ AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts); ++ ++ AV_QSV_ZERO_MEMORY(qsv_decode->m_mfxVideoParam); ++ AV_QSV_ZERO_MEMORY(qsv_decode->m_mfxVideoParam.mfx); ++ qsv_decode->m_mfxVideoParam.mfx.CodecId = MFX_CODEC_AVC; ++ qsv_decode->m_mfxVideoParam.IOPattern = ++ qsv_config_context->io_pattern; ++ ++ qsv_decode->m_mfxVideoParam.AsyncDepth = ++ qsv_config_context->async_depth; ++ ++ AV_QSV_ZERO_MEMORY(qsv_decode->bs); ++ { ++ current_position = avctx->extradata; ++ current_size = avctx->extradata_size; ++ ++ if (!ff_qsv_nal_find_start_code(current_position, current_size)) { ++ ++ while (current_offset <= current_size) { ++ int current_nal_size = ++ (unsigned char) current_position[current_offset] << 8 | ++ (unsigned char) current_position[current_offset + 1]; ++ unsigned char nal_type = ++ (unsigned char) current_position[current_offset + 2] & 0x1F; ++ ++ if (nal_type == NAL_SPS || nal_type == NAL_PPS) { ++ memcpy(&qsv_decode->p_buf[header_size], ff_prefix_code, ++ sizeof(ff_prefix_code)); ++ header_size += sizeof(ff_prefix_code); ++ memcpy(&qsv_decode->p_buf[header_size], ++ ¤t_position[current_offset + 2], ++ current_nal_size); ++ ++ // fix for PPS as it comes after SPS, so - last ++ if (nal_type == NAL_PPS) { ++ // fix of MFXVideoDECODE_DecodeHeader: needs one SLICE to find, any SLICE ++ memcpy(&qsv_decode->p_buf ++ [header_size + current_nal_size], ++ ff_slice_code, current_nal_size); ++ header_size += sizeof(ff_slice_code); ++ } ++ } ++ ++ header_size += current_nal_size; ++ current_offset += current_nal_size + 3; ++ } ++ } else { ++ memcpy(&qsv_decode->p_buf[0], avctx->extradata, ++ avctx->extradata_size); ++ header_size = avctx->extradata_size; ++ memcpy(&qsv_decode->p_buf ++ [header_size], ff_slice_code, sizeof(ff_slice_code)); ++ header_size += sizeof(ff_slice_code); ++ } ++ } ++ ++ qsv_decode->bs.Data = qsv_decode->p_buf; ++ qsv_decode->bs.DataLength = header_size; ++ qsv_decode->bs.MaxLength = qsv_decode->p_buf_max_size; ++ ++ if (qsv_decode->bs.DataLength > qsv_decode->bs.MaxLength) { ++ av_log(avctx, AV_LOG_FATAL, "DataLength > MaxLength\n"); ++ return -1; ++ } ++ ++ sts = MFXVideoDECODE_DecodeHeader(qsv->mfx_session, &qsv_decode->bs, ++ &qsv_decode->m_mfxVideoParam); ++ ++ AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts); ++ ++ qsv_decode->bs.DataLength -= sizeof(ff_slice_code); ++ ++ memset(&qsv_decode->request, 0, sizeof(mfxFrameAllocRequest) * 2); ++ sts = MFXVideoDECODE_QueryIOSurf(qsv->mfx_session, ++ &qsv_decode->m_mfxVideoParam, ++ &qsv_decode->request); ++ ++ AV_QSV_IGNORE_MFX_STS(sts, MFX_WRN_PARTIAL_ACCELERATION); ++ AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts); ++ ++ qsv_decode->surface_num = ++ FFMIN(qsv_decode->request[0].NumFrameSuggested + ++ qsv_config_context->async_depth + ++ qsv_config_context->additional_buffers, AV_QSV_SURFACE_NUM); ++ ++ if (qsv_decode->surface_num <= 0) ++ qsv_decode->surface_num = AV_QSV_SURFACE_NUM; ++ ++ if (qsv_decode->m_mfxVideoParam.IOPattern == ++ MFX_IOPATTERN_OUT_SYSTEM_MEMORY) { ++ ++ // as per non-opaque memory: ++ if (!qsv_config_context->allocators) { ++ av_log(avctx, AV_LOG_INFO, ++ "Using default allocators for QSV decode\n"); ++ ((av_qsv_config *) avctx->hwaccel_context)->allocators = ++ &av_qsv_default_system_allocators; ++ } ++ ++ qsv_config_context->allocators->space = qsv_decode; ++ ++ qsv_decode->request[0].NumFrameMin = qsv_decode->surface_num; ++ qsv_decode->request[0].NumFrameSuggested = qsv_decode->surface_num; ++ ++ qsv_decode->request[0].Type = MFX_MEMTYPE_EXTERNAL_FRAME | MFX_MEMTYPE_FROM_DECODE; ++ // qsv_decode->request[0].Type |= m_bd3dAlloc ? MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET : MFX_MEMTYPE_SYSTEM_MEMORY; ++ qsv_decode->request[0].Type |= MFX_MEMTYPE_SYSTEM_MEMORY; ++ ++ qsv_config_context->allocators-> ++ frame_alloc.Alloc(qsv_config_context->allocators, ++ &qsv_decode->request[0], ++ &qsv_decode->response); ++ } ++ ++ for (int i = 0; i < qsv_decode->surface_num; i++) { ++ qsv_decode->p_surfaces[i] = av_mallocz(sizeof(mfxFrameSurface1)); ++ AV_QSV_CHECK_POINTER(qsv_decode->p_surfaces[i], ++ AVERROR(ENOMEM)); ++ memcpy(&(qsv_decode->p_surfaces[i]->Info), ++ &(qsv_decode->request[0].Info), sizeof(mfxFrameInfo)); ++ ++ // for an external(like DX9/11) based allocation: ++ // we bind: ++ // m_pmfxSurfaces[i].Data.MemId = m_mfxResponse.mids[i]; ++ // else, System memory: ++ if (qsv_decode->m_mfxVideoParam.IOPattern == ++ MFX_IOPATTERN_OUT_SYSTEM_MEMORY) { ++ sts = ++ qsv_config_context->allocators-> ++ frame_alloc.Lock(qsv_config_context->allocators, ++ qsv_decode->response.mids[i], ++ &(qsv_decode->p_surfaces[i]->Data)); ++ AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts); ++ } ++ } ++ ++ qsv_decode->sync_num = FFMIN(qsv_decode->surface_num, AV_QSV_SYNC_NUM); ++ for (int i = 0; i < qsv_decode->sync_num; i++) { ++ qsv_decode->p_syncp[i] = av_mallocz(sizeof(av_qsv_sync)); ++ AV_QSV_CHECK_POINTER(qsv_decode->p_syncp[i], AVERROR(ENOMEM)); ++ qsv_decode->p_syncp[i]->p_sync = av_mallocz(sizeof(mfxSyncPoint)); ++ AV_QSV_CHECK_POINTER(qsv_decode->p_syncp[i]->p_sync, AVERROR(ENOMEM)); ++ } ++ ++ memset(&qsv_decode->ext_opaque_alloc, 0, ++ sizeof(mfxExtOpaqueSurfaceAlloc)); ++ ++ if (qsv_decode->m_mfxVideoParam.IOPattern == ++ MFX_IOPATTERN_OUT_OPAQUE_MEMORY) { ++ qsv_decode->m_mfxVideoParam.NumExtParam = qsv_decode->p_ext_param_num = 1; ++ ++ qsv_decode->p_ext_params = av_mallocz(sizeof(mfxExtBuffer *)*qsv_decode->p_ext_param_num); ++ AV_QSV_CHECK_POINTER(qsv_decode->p_ext_params, AVERROR(ENOMEM)); ++ ++ qsv_decode->m_mfxVideoParam.ExtParam = qsv_decode->p_ext_params; ++ ++ qsv_decode->ext_opaque_alloc.Out.Surfaces = qsv_decode->p_surfaces; ++ qsv_decode->ext_opaque_alloc.Out.NumSurface = qsv_decode->surface_num; ++ qsv_decode->ext_opaque_alloc.Out.Type = qsv_decode->request[0].Type; ++ ++ qsv_decode->ext_opaque_alloc.Header.BufferId = MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION; ++ qsv_decode->ext_opaque_alloc.Header.BufferSz = sizeof(mfxExtOpaqueSurfaceAlloc); ++ qsv_decode->p_ext_params[0] = (mfxExtBuffer *) &qsv_decode->ext_opaque_alloc; ++ } ++ ++ sts = ++ MFXVideoDECODE_Init(qsv->mfx_session, ++ &qsv_decode->m_mfxVideoParam); ++ ++ AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts); ++ ++ qsv_decode->is_init_done = 1; ++ return ret; ++} ++ ++av_cold int ff_qsv_decode_init(AVCodecContext * avctx) ++{ ++ av_qsv_context *qsv; ++ av_qsv_space *qsv_decode; ++ av_qsv_config **qsv_config_context = ++ (av_qsv_config **) & avctx->hwaccel_context; ++ ++ qsv = avctx->priv_data; ++ ++ if (qsv && qsv->dec_space && qsv->dec_space->is_init_done || !avctx->extradata_size) ++ return 0; ++ ++ if(!qsv) ++ qsv = av_mallocz(sizeof(av_qsv_context)); ++ if (!qsv) ++ return AVERROR(ENOMEM); ++ ++ if(!qsv_decode) ++ qsv_decode = av_mallocz(sizeof(av_qsv_space)); ++ if (!qsv_decode){ ++ free(qsv); ++ return AVERROR(ENOMEM); ++ } ++ avctx->priv_data = qsv; ++ qsv->dec_space = qsv_decode; ++ ++ qsv_decode->p_buf_max_size = AV_QSV_BUF_SIZE_DEFAULT; ++ if(!qsv_decode->p_buf) ++ qsv_decode->p_buf = av_malloc(qsv_decode->p_buf_max_size * sizeof(uint8_t)); ++ if (!qsv_decode->p_buf) ++ return AVERROR(ENOMEM); ++ ++ if (!(*qsv_config_context)) { ++ av_log(avctx, AV_LOG_INFO, ++ "Using default config for QSV decode\n"); ++ avctx->hwaccel_context = &av_qsv_default_config; ++ } else { ++ if ((*qsv_config_context)->io_pattern != ++ MFX_IOPATTERN_OUT_OPAQUE_MEMORY ++ && (*qsv_config_context)->io_pattern != ++ MFX_IOPATTERN_OUT_SYSTEM_MEMORY) { ++ av_log_missing_feature( avctx,"Only MFX_IOPATTERN_OUT_OPAQUE_MEMORY and MFX_IOPATTERN_OUT_SYSTEM_MEMORY are currently supported\n",0); ++ return AVERROR_PATCHWELCOME; ++ } ++ } ++ ++ qsv->qsv_config = avctx->hwaccel_context; ++ ++ av_qsv_add_context_usage(qsv, ++ HAVE_THREADS ++ ? (*qsv_config_context)->usage_threaded : ++ HAVE_THREADS); ++ ++ // allocation of p_syncp and p_surfaces inside of ff_qsv_dec_init ++ return ff_qsv_dec_init(avctx); ++} ++ ++static av_cold int qsv_decode_end(AVCodecContext * avctx) ++{ ++ mfxStatus sts = MFX_ERR_NONE; ++ av_qsv_context *qsv = avctx->priv_data; ++ av_qsv_config *qsv_config_context = avctx->hwaccel_context; ++ ++ if (qsv) { ++ av_qsv_space *qsv_decode = qsv->dec_space; ++ if (qsv_decode && qsv_decode->is_init_done) { ++ // todo: change to AV_LOG_INFO ++ av_log(avctx, AV_LOG_QUIET, ++ "qsv_decode report done, max_surfaces: %u/%u , max_syncs: %u/%u\n", ++ qsv_decode->surface_num_max_used, ++ qsv_decode->surface_num, qsv_decode->sync_num_max_used, ++ qsv_decode->sync_num); ++ } ++ ++ if (qsv_config_context ++ && qsv_config_context->io_pattern == ++ MFX_IOPATTERN_OUT_SYSTEM_MEMORY) { ++ if (qsv_config_context->allocators) { ++ sts = ++ qsv_config_context->allocators-> ++ frame_alloc.Free(qsv_config_context->allocators, ++ &qsv_decode->response); ++ AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts); ++ } else { ++ av_log(avctx, AV_LOG_FATAL, ++ "No QSV allocators found for clean up\n"); ++ } ++ } ++ // closing the own resources ++ av_freep(&qsv_decode->p_buf); ++ ++ for (int i = 0; i < qsv_decode->surface_num; i++) { ++ av_freep(&qsv_decode->p_surfaces[i]); ++ } ++ qsv_decode->surface_num = 0; ++ ++ if( qsv_decode->p_ext_param_num || qsv_decode->p_ext_params ) ++ av_freep(&qsv_decode->p_ext_params); ++ qsv_decode->p_ext_param_num = 0; ++ ++ for (int i = 0; i < qsv_decode->sync_num; i++) { ++ av_freep(&qsv_decode->p_syncp[i]->p_sync); ++ av_freep(&qsv_decode->p_syncp[i]); ++ } ++ qsv_decode->sync_num = 0; ++ qsv_decode->is_init_done = 0; ++ ++ av_freep(&qsv->dec_space); ++ ++ // closing commong stuff ++ av_qsv_context_clean(qsv); ++ } ++ ++ return 0; ++} ++ ++static int qsv_decode_frame(AVCodecContext * avctx, void *data, ++ int *data_size, AVPacket * avpkt) ++{ ++ mfxStatus sts = MFX_ERR_NONE; ++ av_qsv_context *qsv = avctx->priv_data; ++ av_qsv_space *qsv_decode; ++ av_qsv_config *qsv_config_context = avctx->hwaccel_context; ++ int *got_picture_ptr = data_size; ++ int ret_value = 1; ++ uint8_t *current_position = avpkt->data; ++ int current_size = avpkt->size; ++ int frame_processed = 0; ++ size_t frame_length = 0; ++ int surface_idx = 0; ++ int extra_data_workaround = 0; ++ ++ int sync_idx = 0; ++ int current_nal_size; ++ unsigned char nal_type; ++ av_qsv_stage *new_stage = 0; ++ mfxBitstream *input_bs = NULL; ++ size_t current_offset = 2; ++ av_qsv_list *qsv_atom = 0; ++ av_qsv_list *pipe = 0; ++ ++ AVFrame *picture = (AVFrame *) data; ++ ++ *got_picture_ptr = 0; ++ ++ qsv = avctx->priv_data; ++ if(!qsv){ ++ extra_data_workaround = !avctx->extradata_size; ++ if(extra_data_workaround){ ++ avctx->extradata = avpkt->data; ++ avctx->extradata_size = avpkt->size; ++ } ++ sts = ff_qsv_decode_init(avctx); ++ qsv = avctx->priv_data; ++ if(extra_data_workaround){ ++ avctx->extradata = 0; ++ avctx->extradata_size = 0; ++ } ++ if(sts<0){ ++ ff_qsv_dec_init_clean(avctx); ++ *got_picture_ptr = 0; ++ return sts; ++ } ++ } ++ qsv_decode = qsv->dec_space; ++ ++ if (qsv_decode->bs.DataOffset + qsv_decode->bs.DataLength + ++ current_size > qsv_decode->bs.MaxLength) { ++ memmove(&qsv_decode->bs.Data[0], ++ qsv_decode->bs.Data + qsv_decode->bs.DataOffset, ++ qsv_decode->bs.DataLength); ++ qsv_decode->bs.DataOffset = 0; ++ } ++ ++ if (current_size) { ++ if(qsv->is_anex == ANEX_UNKNOWN){ ++ if (ff_qsv_nal_find_start_code(current_position, current_size) && current_position == avpkt->data) ++ qsv->is_anex = ANEX_PREFIX; ++ else ++ qsv->is_anex = ANEX_NO_PREFIX; ++ } ++ if (qsv->is_anex == ANEX_PREFIX){ ++ memcpy(&qsv_decode->bs.Data[0] + ++ qsv_decode->bs.DataLength + ++ qsv_decode->bs.DataOffset, ++ avpkt->data, ++ avpkt->size); ++ qsv_decode->bs.DataLength += avpkt->size; ++ frame_length += avpkt->size; ++ } ++ else ++ while (current_offset <= current_size) { ++ current_nal_size = ++ ((unsigned char) current_position[current_offset - 2] << 24 | ++ (unsigned char) current_position[current_offset - 1] << 16 | ++ (unsigned char) current_position[current_offset] << 8 | ++ (unsigned char) current_position[current_offset + 1]) - 1; ++ nal_type = ++ (unsigned char) current_position[current_offset + 2] & 0x1F; ++ { ++ frame_length += current_nal_size; ++ memcpy(&qsv_decode->bs.Data[0] + ++ qsv_decode->bs.DataLength + ++ qsv_decode->bs.DataOffset, ff_prefix_code, ++ sizeof(ff_prefix_code)); ++ qsv_decode->bs.DataLength += sizeof(ff_prefix_code); ++ memcpy(&qsv_decode->bs.Data[0] + ++ qsv_decode->bs.DataLength + ++ qsv_decode->bs.DataOffset, ++ ¤t_position[current_offset + 2], ++ current_nal_size + 1); ++ qsv_decode->bs.DataLength += current_nal_size + 1; ++ } ++ current_offset += current_nal_size + 5; ++ } ++ ++ if (qsv_decode->bs.DataLength > qsv_decode->bs.MaxLength) { ++ av_log(avctx, AV_LOG_FATAL, "DataLength > MaxLength\n"); ++ return -1; ++ } ++ } ++ ++ if (frame_length || current_size == 0) { ++ ++ qsv_decode->bs.TimeStamp = avpkt->pts; ++ ++ //not a drain ++ if ((current_size || qsv_decode->bs.DataLength)) ++ av_qsv_dts_ordered_insert(qsv, 0, 0, qsv_decode->bs.TimeStamp, 0); ++ ++ sts = MFX_ERR_NONE; ++ // ignore warnings, where warnings >0 , and not error codes <0 ++ while (MFX_ERR_NONE <= sts || MFX_ERR_MORE_SURFACE == sts ++ || MFX_WRN_DEVICE_BUSY == sts) { ++ ++ if (MFX_ERR_MORE_SURFACE == sts || MFX_ERR_NONE == sts) { ++ surface_idx = ++ av_qsv_get_free_surface(qsv_decode, qsv, ++ &qsv_decode->request[0].Info, ++ QSV_PART_ANY); ++ ++ if (surface_idx == -1) { ++ *got_picture_ptr = 0; ++ return 0; ++ } ++ } ++ ++ if (MFX_WRN_DEVICE_BUSY == sts) ++ av_qsv_sleep(10); ++ ++ sync_idx = av_qsv_get_free_sync(qsv_decode, qsv); ++ ++ if (sync_idx == -1) { ++ *got_picture_ptr = 0; ++ return 0; ++ } ++ new_stage = av_qsv_stage_init(); ++ input_bs = NULL; ++ // if to drain last ones ++ if (current_size || qsv_decode->bs.DataLength) ++ input_bs = &qsv_decode->bs; ++ // Decode a frame asynchronously (returns immediately) ++ // very first IDR / SLICE should be with SPS/PPS ++ sts = MFXVideoDECODE_DecodeFrameAsync(qsv->mfx_session, input_bs, ++ qsv_decode->p_surfaces ++ [surface_idx], ++ &new_stage->out.p_surface, ++ qsv_decode->p_syncp[sync_idx]->p_sync); ++ ++ new_stage->out.sync = qsv_decode->p_syncp[sync_idx]; ++ // have some results ++ if (MFX_ERR_NONE <= sts && MFX_WRN_DEVICE_BUSY != sts && ++ MFX_WRN_VIDEO_PARAM_CHANGED != sts) { ++ ++ ff_qsv_atomic_inc(&(new_stage->out.p_surface->Data.Locked)); ++ ++ new_stage->type = AV_QSV_DECODE; ++ new_stage->in.p_bs = input_bs; ++ new_stage->in.p_surface = qsv_decode->p_surfaces[surface_idx]; ++ ++ pipe = av_qsv_list_init(HAVE_THREADS ? qsv_config_context->usage_threaded : HAVE_THREADS); ++ av_qsv_add_stagee(&pipe, new_stage, ++ HAVE_THREADS ? ++ qsv_config_context->usage_threaded : ++ HAVE_THREADS); ++ ++ av_qsv_list_add(qsv->pipes, pipe); ++ qsv_atom = pipe; ++ ++ // usage for forced decode sync and results, can be avoided if sync done by next stage ++ // also note wait time for Sync and possible usage with MFX_WRN_IN_EXECUTION check ++ if (qsv_config_context->sync_need) { ++ sts = ++ MFXVideoCORE_SyncOperation(qsv->mfx_session, ++ qsv_decode->p_syncp[sync_idx]->p_sync, ++ qsv_config_context->sync_need); ++ AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts); ++ ++ // no need to wait more -> force off ++ ff_qsv_atomic_dec(&qsv_decode->p_syncp[sync_idx]->in_use); ++ new_stage->out.sync = 0; ++ } ++ ++ sts = MFX_ERR_NONE; ++ break; ++ } ++ av_qsv_stage_clean(&new_stage); ++ ++ /* ++ Can be because of: ++ - runtime situation: ++ - drain procedure: ++ At the end of the bitstream, the application continuously calls the MFXVideoDECODE_DecodeFrameAsync function with a ++ NULL bitstream pointer to drain any remaining frames cached within the Intel ++ Media SDK decoder, until the function returns MFX_ERR_MORE_DATA. ++ */ ++ if (MFX_ERR_MORE_DATA == sts) { ++ // not a drain ++ if (current_size) { ++ *got_picture_ptr = 0; ++ return avpkt->size; ++ } ++ // drain ++ break; ++ } ++ if (MFX_ERR_MORE_SURFACE == sts ){ ++ continue; ++ } ++ ++ AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts); ++ } ++ ++ frame_processed = 1; ++ } ++ ++ if (frame_processed) { ++ ++ if (current_size) { ++ *got_picture_ptr = 1; ++ ret_value = avpkt->size; ++ } else { ++ if (MFX_ERR_MORE_DATA != sts) { ++ *got_picture_ptr = 1; ++ ret_value = avpkt->size; ++ } else { ++ *got_picture_ptr = 0; ++ return 0; ++ } ++ } ++ ++ picture->pkt_pts = new_stage->out.p_surface->Data.TimeStamp; ++ picture->pts = new_stage->out.p_surface->Data.TimeStamp; ++ ++ picture->repeat_pict = (qsv_decode->m_mfxVideoParam.mfx.FrameInfo.PicStruct & MFX_PICSTRUCT_FIELD_REPEATED); ++ picture->interlaced_frame = !(qsv_decode->m_mfxVideoParam.mfx.FrameInfo.PicStruct & MFX_PICSTRUCT_PROGRESSIVE); ++ picture->top_field_first = (qsv_decode->m_mfxVideoParam.mfx.FrameInfo.PicStruct & MFX_PICSTRUCT_FIELD_TFF); ++ ++ // since we do not know it yet from MSDK, let's do just a simple way for now ++ picture->key_frame = (avctx->frame_number == 0) ? 1 : 0; ++ ++ if (qsv_decode->m_mfxVideoParam.IOPattern == MFX_IOPATTERN_OUT_SYSTEM_MEMORY) { ++ picture->data[0] = new_stage->out.p_surface->Data.Y; ++ picture->data[1] = new_stage->out.p_surface->Data.VU; ++ picture->linesize[0] = new_stage->out.p_surface->Info.Width; ++ picture->linesize[1] = new_stage->out.p_surface->Info.Width; ++ } else { ++ picture->data[0] = 0; ++ picture->data[1] = 0; ++ picture->linesize[0] = 0; ++ picture->linesize[1] = 0; ++ } ++ ++ picture->data[2] = qsv_atom; ++ picture->linesize[2] = 0; ++ } ++ ++ return ret_value; ++} ++ ++// Will be called when seeking ++static void qsv_flush_dpb(AVCodecContext * avctx) ++{ ++ av_qsv_context *qsv = avctx->priv_data; ++ av_qsv_space *qsv_decode = qsv->dec_space; ++ ++ qsv_decode->bs.DataOffset = 0; ++ qsv_decode->bs.DataLength = 0; ++ qsv_decode->bs.MaxLength = qsv_decode->p_buf_max_size; ++} ++ ++ ++mfxStatus ff_qsv_mem_frame_alloc(mfxHDL pthis, ++ mfxFrameAllocRequest * request, ++ mfxFrameAllocResponse * response) ++{ ++ mfxStatus sts = MFX_ERR_NONE; ++ ++ mfxU32 numAllocated = 0; ++ ++ mfxU32 width = AV_QSV_ALIGN32(request->Info.Width); ++ mfxU32 height = AV_QSV_ALIGN32(request->Info.Height); ++ mfxU32 nbytes; ++ ++ av_qsv_allocators_space *this_alloc = (av_qsv_allocators_space *) pthis; ++ av_qsv_alloc_frame *fs; ++ ++ if (!this_alloc->space) ++ return MFX_ERR_NOT_INITIALIZED; ++ ++ switch (request->Info.FourCC) { ++ case MFX_FOURCC_YV12: ++ case MFX_FOURCC_NV12: ++ nbytes = ++ width * height + (width >> 1) * (height >> 1) + ++ (width >> 1) * (height >> 1); ++ break; ++ case MFX_FOURCC_RGB3: ++ nbytes = width * height + width * height + width * height; ++ break; ++ case MFX_FOURCC_RGB4: ++ nbytes = ++ width * height + width * height + width * height + ++ width * height; ++ break; ++ case MFX_FOURCC_YUY2: ++ nbytes = ++ width * height + (width >> 1) * (height) + ++ (width >> 1) * (height); ++ break; ++ default: ++ return MFX_ERR_UNSUPPORTED; ++ } ++ ++ this_alloc->space->mids = ++ av_malloc(sizeof(mfxMemId) * request->NumFrameSuggested); ++ if (!this_alloc->space->mids) ++ return MFX_ERR_MEMORY_ALLOC; ++ ++ // allocate frames ++ for (numAllocated = 0; numAllocated < request->NumFrameSuggested; ++ numAllocated++) { ++ sts = ++ this_alloc->buffer_alloc.Alloc(this_alloc->buffer_alloc.pthis, ++ nbytes + ++ AV_QSV_ALIGN32(sizeof ++ (av_qsv_alloc_frame)), ++ request->Type, ++ &(this_alloc-> ++ space->mids[numAllocated])); ++ ++ if (MFX_ERR_NONE != sts) ++ break; ++ ++ sts = ++ this_alloc->buffer_alloc.Lock(this_alloc->buffer_alloc.pthis, ++ this_alloc-> ++ space->mids[numAllocated], ++ (mfxU8 **) & fs); ++ ++ if (MFX_ERR_NONE != sts) ++ break; ++ ++ fs->id = AV_QSV_ID_FRAME; ++ fs->info = request->Info; ++ this_alloc->buffer_alloc.Unlock(this_alloc->buffer_alloc.pthis, ++ this_alloc-> ++ space->mids[numAllocated]); ++ } ++ ++ // check the number of allocated frames ++ if (numAllocated < request->NumFrameMin) ++ return MFX_ERR_MEMORY_ALLOC; ++ ++ response->NumFrameActual = (mfxU16) numAllocated; ++ response->mids = this_alloc->space->mids; ++ ++ return MFX_ERR_NONE; ++} ++ ++mfxStatus ff_qsv_mem_frame_lock(mfxHDL pthis, mfxMemId mid, ++ mfxFrameData * ptr) ++{ ++ mfxStatus sts = MFX_ERR_NONE; ++ av_qsv_alloc_frame *fs = 0; ++ mfxU16 width; ++ mfxU16 height; ++ ++ av_qsv_allocators_space *this_alloc = (av_qsv_allocators_space *) pthis; ++ ++ if (!this_alloc->space) ++ return MFX_ERR_NOT_INITIALIZED; ++ if (!ptr) ++ return MFX_ERR_NULL_PTR; ++ ++ ++ sts = ++ this_alloc->buffer_alloc.Lock(this_alloc->buffer_alloc.pthis, mid, ++ (mfxU8 **) & fs); ++ ++ if (MFX_ERR_NONE != sts) ++ return sts; ++ ++ if (AV_QSV_ID_FRAME != fs->id) { ++ this_alloc->buffer_alloc.Unlock(this_alloc->buffer_alloc.pthis, ++ mid); ++ return MFX_ERR_INVALID_HANDLE; ++ } ++ ++ width = (mfxU16) AV_QSV_ALIGN32(fs->info.Width); ++ height = (mfxU16) AV_QSV_ALIGN32(fs->info.Height); ++ ptr->B = ptr->Y = ++ (mfxU8 *) fs + AV_QSV_ALIGN32(sizeof(av_qsv_allocators_space)); ++ ++ switch (fs->info.FourCC) { ++ case MFX_FOURCC_NV12: ++ ptr->U = ptr->Y + width * height; ++ ptr->V = ptr->U + 1; ++ ptr->Pitch = width; ++ break; ++ case MFX_FOURCC_YV12: ++ ptr->V = ptr->Y + width * height; ++ ptr->U = ptr->V + (width >> 1) * (height >> 1); ++ ptr->Pitch = width; ++ break; ++ case MFX_FOURCC_YUY2: ++ ptr->U = ptr->Y + 1; ++ ptr->V = ptr->Y + 3; ++ ptr->Pitch = 2 * width; ++ break; ++ case MFX_FOURCC_RGB3: ++ ptr->G = ptr->B + 1; ++ ptr->R = ptr->B + 2; ++ ptr->Pitch = 3 * width; ++ break; ++ case MFX_FOURCC_RGB4: ++ ptr->G = ptr->B + 1; ++ ptr->R = ptr->B + 2; ++ ptr->A = ptr->B + 3; ++ ptr->Pitch = 4 * width; ++ break; ++ default: ++ return MFX_ERR_UNSUPPORTED; ++ } ++ ++ return MFX_ERR_NONE; ++} ++ ++mfxStatus ff_qsv_mem_frame_unlock(mfxHDL pthis, mfxMemId mid, ++ mfxFrameData * ptr) ++{ ++ mfxStatus sts = MFX_ERR_NONE; ++ av_qsv_allocators_space *this_alloc = (av_qsv_allocators_space *) pthis; ++ ++ sts = ++ this_alloc->buffer_alloc.Unlock(this_alloc->buffer_alloc.pthis, ++ mid); ++ ++ if (MFX_ERR_NONE != sts) ++ return sts; ++ ++ if (NULL != ptr) { ++ ptr->Pitch = 0; ++ ptr->Y = 0; ++ ptr->U = 0; ++ ptr->V = 0; ++ } ++ ++ return MFX_ERR_NONE; ++} ++ ++mfxStatus ff_qsv_mem_frame_getHDL(mfxHDL pthis, mfxMemId mid, ++ mfxHDL * handle) ++{ ++ return MFX_ERR_UNSUPPORTED; ++} ++ ++mfxStatus ff_qsv_mem_frame_free(mfxHDL pthis, ++ mfxFrameAllocResponse * response) ++{ ++ mfxStatus sts = MFX_ERR_NONE; ++ av_qsv_allocators_space *this_alloc = (av_qsv_allocators_space *) pthis; ++ mfxU32 i; ++ ++ if (!response) ++ return MFX_ERR_NULL_PTR; ++ ++ if (!this_alloc->space) ++ return MFX_ERR_NOT_INITIALIZED; ++ ++ if (response->mids) ++ for (i = 0; i < response->NumFrameActual; i++) { ++ if (response->mids[i]) { ++ sts = ++ this_alloc->buffer_alloc.Free(this_alloc-> ++ buffer_alloc.pthis, ++ response->mids[i]); ++ if (MFX_ERR_NONE != sts) ++ return sts; ++ } ++ } ++ ++ av_freep(&response->mids); ++ ++ return sts; ++} ++ ++ ++mfxStatus ff_qsv_mem_buffer_alloc(mfxHDL pthis, mfxU32 nbytes, mfxU16 type, ++ mfxMemId * mid) ++{ ++ av_qsv_alloc_buffer *bs; ++ mfxU32 header_size; ++ mfxU8 *buffer_ptr; ++ ++ if (!mid) ++ return MFX_ERR_NULL_PTR; ++ ++ if (0 == (type & MFX_MEMTYPE_SYSTEM_MEMORY)) ++ return MFX_ERR_UNSUPPORTED; ++ ++ header_size = AV_QSV_ALIGN32(sizeof(av_qsv_alloc_buffer)); ++ buffer_ptr = (mfxU8 *) av_malloc(header_size + nbytes); ++ ++ if (!buffer_ptr) ++ return MFX_ERR_MEMORY_ALLOC; ++ ++ bs = (av_qsv_alloc_buffer *) buffer_ptr; ++ bs->id = AV_QSV_ID_BUFFER; ++ bs->type = type; ++ bs->nbytes = nbytes; ++ *mid = (mfxHDL) bs; ++ return MFX_ERR_NONE; ++} ++ ++mfxStatus ff_qsv_mem_buffer_lock(mfxHDL pthis, mfxMemId mid, mfxU8 ** ptr) ++{ ++ av_qsv_alloc_buffer *bs; ++ ++ if (!ptr) ++ return MFX_ERR_NULL_PTR; ++ ++ bs = (av_qsv_alloc_buffer *) mid; ++ ++ if (!bs) ++ return MFX_ERR_INVALID_HANDLE; ++ if (AV_QSV_ID_BUFFER != bs->id) ++ return MFX_ERR_INVALID_HANDLE; ++ ++ *ptr = (mfxU8 *) bs + AV_QSV_ALIGN32(sizeof(av_qsv_alloc_buffer)); ++ return MFX_ERR_NONE; ++} ++ ++mfxStatus ff_qsv_mem_buffer_unlock(mfxHDL pthis, mfxMemId mid) ++{ ++ av_qsv_alloc_buffer *bs = (av_qsv_alloc_buffer *) mid; ++ ++ if (!bs || AV_QSV_ID_BUFFER != bs->id) ++ return MFX_ERR_INVALID_HANDLE; ++ ++ return MFX_ERR_NONE; ++} ++ ++mfxStatus ff_qsv_mem_buffer_free(mfxHDL pthis, mfxMemId mid) ++{ ++ av_qsv_alloc_buffer *bs = (av_qsv_alloc_buffer *) mid; ++ if (!bs || AV_QSV_ID_BUFFER != bs->id) ++ return MFX_ERR_INVALID_HANDLE; ++ ++ av_freep(&bs); ++ return MFX_ERR_NONE; ++} ++ ++ ++AVCodec ff_h264_qsv_decoder = { ++ .name = "h264_qsv", ++ .type = AVMEDIA_TYPE_VIDEO, ++ .id = AV_CODEC_ID_H264, ++ .init = ff_qsv_decode_init, ++ .close = qsv_decode_end, ++ .decode = qsv_decode_frame, ++ .capabilities = CODEC_CAP_DR1 | CODEC_CAP_DELAY, ++ .flush = qsv_flush_dpb, ++ .long_name = NULL_IF_CONFIG_SMALL("H.264 / AVC / Intel QSV"), ++ .pix_fmts = (const enum PixelFormat[]) {AV_PIX_FMT_QSV_H264, ++ AV_PIX_FMT_NONE}, ++}; +diff -Naur ../../libav-v9.6/libavcodec/qsv_h264.h ./libavcodec/qsv_h264.h +--- ../../libav-v9.6/libavcodec/qsv_h264.h 1970-01-01 01:00:00.000000000 +0100 ++++ ./libavcodec/qsv_h264.h 2013-08-19 21:32:01.710244809 +0200 +@@ -0,0 +1,65 @@ ++/* ********************************************************************* *\ ++ ++Copyright (C) 2013 Intel Corporation. All rights reserved. ++ ++Redistribution and use in source and binary forms, with or without ++modification, are permitted provided that the following conditions are met: ++- Redistributions of source code must retain the above copyright notice, ++this list of conditions and the following disclaimer. ++- Redistributions in binary form must reproduce the above copyright notice, ++this list of conditions and the following disclaimer in the documentation ++and/or other materials provided with the distribution. ++- Neither the name of Intel Corporation nor the names of its contributors ++may be used to endorse or promote products derived from this software ++without specific prior written permission. ++ ++THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION "AS IS" AND ANY EXPRESS OR ++IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, ++INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ ++\* ********************************************************************* */ ++ ++#ifndef AVCODEC_QSV_H264_H ++#define AVCODEC_QSV_H264_H ++ ++#include "qsv.h" ++ ++int ff_qsv_dec_init(AVCodecContext *); ++int ff_qsv_nal_find_start_code(uint8_t * pb, size_t size); ++ ++int ff_qsv_dec_init_clean(AVCodecContext *avctx); ++av_cold int ff_qsv_decode_init(AVCodecContext * avctx); ++static av_cold int qsv_decode_end(AVCodecContext * avctx); ++static int qsv_decode_frame(AVCodecContext * avctx, void *data, ++ int *data_size, AVPacket * avpkt); ++static void qsv_flush_dpb(AVCodecContext * avctx); ++ ++ ++// Default for SYSTEM MEMORY ++// as from MFXFrameAllocator ++mfxStatus ff_qsv_mem_frame_alloc(mfxHDL pthis, ++ mfxFrameAllocRequest * request, ++ mfxFrameAllocResponse * response); ++mfxStatus ff_qsv_mem_frame_lock(mfxHDL pthis, mfxMemId mid, ++ mfxFrameData * ptr); ++mfxStatus ff_qsv_mem_frame_unlock(mfxHDL pthis, mfxMemId mid, ++ mfxFrameData * ptr); ++mfxStatus ff_qsv_mem_frame_getHDL(mfxHDL pthis, mfxMemId mid, ++ mfxHDL * handle); ++mfxStatus ff_qsv_mem_frame_free(mfxHDL pthis, ++ mfxFrameAllocResponse * response); ++// as from mfxBufferAllocator ++mfxStatus ff_qsv_mem_buffer_alloc(mfxHDL pthis, mfxU32 nbytes, mfxU16 type, ++ mfxMemId * mid); ++mfxStatus ff_qsv_mem_buffer_lock(mfxHDL pthis, mfxMemId mid, mfxU8 ** ptr); ++mfxStatus ff_qsv_mem_buffer_unlock(mfxHDL pthis, mfxMemId mid); ++mfxStatus ff_qsv_mem_buffer_free(mfxHDL pthis, mfxMemId mid); ++ ++#endif //AVCODEC_QSV_H264_H +diff -Naur ../../libav-v9.6/libavutil/pixfmt.h ./libavutil/pixfmt.h +--- ../../libav-v9.6/libavutil/pixfmt.h 2013-05-12 08:39:07.000000000 +0200 ++++ ./libavutil/pixfmt.h 2013-08-14 10:48:00.522497405 +0200 +@@ -178,6 +178,7 @@ + AV_PIX_FMT_YUVA422P16LE, ///< planar YUV 4:2:2 48bpp, (1 Cr & Cb sample per 2x1 Y & A samples, little-endian) + AV_PIX_FMT_YUVA444P16BE, ///< planar YUV 4:4:4 64bpp, (1 Cr & Cb sample per 1x1 Y & A samples, big-endian) + AV_PIX_FMT_YUVA444P16LE, ///< planar YUV 4:4:4 64bpp, (1 Cr & Cb sample per 1x1 Y & A samples, little-endian) ++ AV_PIX_FMT_QSV_H264, ///< H.264 HW decoding with QSV, data[2] contains qsv_atom information for MFX_IOPATTERN_OUT_OPAQUE_MEMORY, MFX_IOPATTERN_OUT_VIDEO_MEMORY + AV_PIX_FMT_NB, ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions + + #if FF_API_PIX_FMT diff --git a/contrib/ffmpeg/A04-aacenc.patch b/contrib/ffmpeg/A04-aacenc.patch new file mode 100644 index 000000000..b58441a17 --- /dev/null +++ b/contrib/ffmpeg/A04-aacenc.patch @@ -0,0 +1,82 @@ +commit 8bbdd20a293eab2cfac9f332613ead02a4e3c0c2 +Author: Claudio Freire <[email protected]> +Date: Sun May 12 09:38:40 2013 +0200 + + aacenc: Fix erasure of surround channels + + This was due to a miscomputation of s->cur_channel, which led to + psy-based encoders using the psy coefficients for the wrong channel. + + Signed-off-by: Martin Storsjö <[email protected]> + +diff --git a/libavcodec/aacenc.c b/libavcodec/aacenc.c +index 60eca59..b2ad47b 100644 +--- a/libavcodec/aacenc.c ++++ b/libavcodec/aacenc.c +@@ -597,7 +597,7 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, + coeffs[ch] = cpe->ch[ch].coeffs; + s->psy.model->analyze(&s->psy, start_ch, coeffs, wi); + for (ch = 0; ch < chans; ch++) { +- s->cur_channel = start_ch * 2 + ch; ++ s->cur_channel = start_ch + ch; + s->coder->search_for_quantizers(avctx, s, &cpe->ch[ch], s->lambda); + } + cpe->common_window = 0; +@@ -613,7 +613,7 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, + } + } + } +- s->cur_channel = start_ch * 2; ++ s->cur_channel = start_ch; + if (s->options.stereo_mode && cpe->common_window) { + if (s->options.stereo_mode > 0) { + IndividualChannelStream *ics = &cpe->ch[0].ics; + +commit f4d0a63b5b5c682c18df3bba730f97a9067408ba +Author: Claudio Freire <[email protected]> +Date: Sat May 4 18:36:37 2013 -0300 + + aacenc: Fix target bitrate for twoloop quantiser search + + This fixes a case where multichannel bitrate isn't accurately + targetted by psy model alone, never achieving the target bitrate. + + Signed-off-by: Martin Storsjö <[email protected]> + +diff --git a/libavcodec/aaccoder.c b/libavcodec/aaccoder.c +index d65d8d9..35b98a9 100644 +--- a/libavcodec/aaccoder.c ++++ b/libavcodec/aaccoder.c +@@ -710,7 +710,7 @@ static void search_for_quantizers_twoloop(AVCodecContext *avctx, + const float lambda) + { + int start = 0, i, w, w2, g; +- int destbits = avctx->bit_rate * 1024.0 / avctx->sample_rate / avctx->channels; ++ int destbits = avctx->bit_rate * 1024.0 / avctx->sample_rate / avctx->channels * (lambda / 120.f); + float dists[128] = { 0 }, uplims[128]; + float maxvals[128]; + int fflag, minscaler; + +commit 7c71ada4cad3c6aab5fa24155c379465c41cfd76 +Author: Claudio Freire <[email protected]> +Date: Sat May 4 18:35:49 2013 -0300 + + aacenc: Fix a rounding bug in aacpsy channel bitrate computation + + Signed-off-by: Martin Storsjö <[email protected]> + +diff --git a/libavcodec/aacpsy.c b/libavcodec/aacpsy.c +index 6f1ac05..66cf6d5 100644 +--- a/libavcodec/aacpsy.c ++++ b/libavcodec/aacpsy.c +@@ -312,7 +312,7 @@ static av_cold int psy_3gpp_init(FFPsyContext *ctx) { + AacPsyCoeffs *coeffs = pctx->psy_coef[j]; + const uint8_t *band_sizes = ctx->bands[j]; + float line_to_frequency = ctx->avctx->sample_rate / (j ? 256.f : 2048.0f); +- float avg_chan_bits = chan_bitrate / ctx->avctx->sample_rate * (j ? 128.0f : 1024.0f); ++ float avg_chan_bits = chan_bitrate * (j ? 128.0f : 1024.0f) / ctx->avctx->sample_rate; + /* reference encoder uses 2.4% here instead of 60% like the spec says */ + float bark_pe = 0.024f * PSY_3GPP_BITS_TO_PE(avg_chan_bits) / num_bark; + float en_spread_low = j ? PSY_3GPP_EN_SPREAD_LOW_S : PSY_3GPP_EN_SPREAD_LOW_L; + + diff --git a/contrib/ffmpeg/A05-mkv-chapters.patch b/contrib/ffmpeg/A05-mkv-chapters.patch new file mode 100644 index 000000000..f4082be1d --- /dev/null +++ b/contrib/ffmpeg/A05-mkv-chapters.patch @@ -0,0 +1,57 @@ +From c4d83dfad34d69a86bf04ded97ae3fda087bfa25 Mon Sep 17 00:00:00 2001 +From: John Stebbins <[email protected]> +Date: Fri, 10 May 2013 08:45:55 -0700 +Subject: [PATCH 1/9] matroskaenc: Allow chapters to be written in trailer + +This allows creation of frame accurate chapter marks from sources like +DVD and BD where the precise chapter location is not known until the +chapter mark has been reached during reading. +--- + libavformat/matroskaenc.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c +index b37d10c..99de151 100644 +--- a/libavformat/matroskaenc.c ++++ b/libavformat/matroskaenc.c +@@ -94,6 +94,7 @@ typedef struct MatroskaMuxContext { + AVPacket cur_audio_pkt; + + int have_attachments; ++ int wrote_chapters; + } MatroskaMuxContext; + + +@@ -688,7 +689,7 @@ static int mkv_write_chapters(AVFormatContext *s) + AVRational scale = {1, 1E9}; + int i, ret; + +- if (!s->nb_chapters) ++ if (!s->nb_chapters || mkv->wrote_chapters) + return 0; + + ret = mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_CHAPTERS, avio_tell(pb)); +@@ -721,6 +722,8 @@ static int mkv_write_chapters(AVFormatContext *s) + } + end_ebml_master(pb, editionentry); + end_ebml_master(pb, chapters); ++ ++ mkv->wrote_chapters = 1; + return 0; + } + +@@ -1259,6 +1262,11 @@ static int mkv_write_trailer(AVFormatContext *s) + end_ebml_master(pb, mkv->cluster); + } + ++ if (mkv->mode != MODE_WEBM) { ++ ret = mkv_write_chapters(s); ++ if (ret < 0) return ret; ++ } ++ + if (pb->seekable) { + if (mkv->cues->num_entries) { + cuespos = mkv_write_cues(pb, mkv->cues, s->nb_streams); +-- +1.8.1.4 + diff --git a/contrib/ffmpeg/A06-mkv-default-subtitle.patch b/contrib/ffmpeg/A06-mkv-default-subtitle.patch new file mode 100644 index 000000000..9074a3443 --- /dev/null +++ b/contrib/ffmpeg/A06-mkv-default-subtitle.patch @@ -0,0 +1,30 @@ +From f1febbdddc573c7684e1761abfe568ebfcfcdcd1 Mon Sep 17 00:00:00 2001 +From: John Stebbins <[email protected]> +Date: Fri, 10 May 2013 08:49:58 -0700 +Subject: [PATCH 3/9] matroskaenc: Fix writing TRACKDEFAULTFLAG + +The element was only being written when the value == 1. But the default +value of this element is 1, so this has no useful effect. This element +needs to be written when the value == 0. +--- + libavformat/matroskaenc.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c +index 4858af5..358ba66 100644 +--- a/libavformat/matroskaenc.c ++++ b/libavformat/matroskaenc.c +@@ -568,7 +568,9 @@ static int mkv_write_tracks(AVFormatContext *s) + tag = av_dict_get(st->metadata, "language", NULL, 0); + put_ebml_string(pb, MATROSKA_ID_TRACKLANGUAGE, tag ? tag->value:"und"); + +- if (st->disposition) ++ // The default value for TRACKFLAGDEFAULT is 1, so add element ++ // if we need to clear it. ++ if (!(st->disposition & AV_DISPOSITION_DEFAULT)) + put_ebml_uint(pb, MATROSKA_ID_TRACKFLAGDEFAULT, !!(st->disposition & AV_DISPOSITION_DEFAULT)); + + // look for a codec ID string specific to mkv to use, +-- +1.8.1.4 + diff --git a/contrib/ffmpeg/A07-mp4-chapters.patch b/contrib/ffmpeg/A07-mp4-chapters.patch new file mode 100644 index 000000000..0fec0eaf9 --- /dev/null +++ b/contrib/ffmpeg/A07-mp4-chapters.patch @@ -0,0 +1,60 @@ +From 36bdd52964ef68532eea50a81431c0c4c9f329e5 Mon Sep 17 00:00:00 2001 +From: John Stebbins <[email protected]> +Date: Fri, 10 May 2013 08:51:46 -0700 +Subject: [PATCH 4/9] movenc: Allow chapters to be written in trailer + +This allows creation of frame accurate chapter marks from sources +like DVD and BD where the precise chapter location is not known until +the chapter mark has been reached during reading. +--- + libavformat/movenc.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/libavformat/movenc.c b/libavformat/movenc.c +index 496158c..f41f8d7 100644 +--- a/libavformat/movenc.c ++++ b/libavformat/movenc.c +@@ -3038,7 +3038,7 @@ static int mov_write_header(AVFormatContext *s) + } + + mov->nb_streams = s->nb_streams; +- if (mov->mode & (MODE_MOV|MODE_IPOD) && s->nb_chapters) ++ if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters) + mov->chapter_track = mov->nb_streams++; + + if (mov->flags & FF_MOV_FLAG_RTP_HINT) { +@@ -3053,7 +3053,9 @@ static int mov_write_header(AVFormatContext *s) + } + } + +- mov->tracks = av_mallocz(mov->nb_streams*sizeof(*mov->tracks)); ++ // Reserve an extra stream for chapters for the case where chapters ++ // are written in the trailer ++ mov->tracks = av_mallocz((mov->nb_streams+1)*sizeof(*mov->tracks)); + if (!mov->tracks) + return AVERROR(ENOMEM); + +@@ -3189,8 +3191,19 @@ static int mov_write_trailer(AVFormatContext *s) + AVIOContext *pb = s->pb; + int res = 0; + int i; ++ int64_t moov_pos; ++ ++ // If there were no chapters when the header was written, but there ++ // are chapters now, write them in the trailer. This only works ++ // when we are not doing fragments. ++ if (!mov->chapter_track && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) { ++ if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters) { ++ mov->chapter_track = mov->nb_streams++; ++ mov_create_chapter_track(s, mov->chapter_track); ++ } ++ } + +- int64_t moov_pos = avio_tell(pb); ++ moov_pos = avio_tell(pb); + + if (!(mov->flags & FF_MOV_FLAG_FRAGMENT)) { + /* Write size of mdat tag */ +-- +1.8.1.4 + diff --git a/contrib/ffmpeg/A08-mp4-faststart.patch b/contrib/ffmpeg/A08-mp4-faststart.patch new file mode 100644 index 000000000..c4d8d706b --- /dev/null +++ b/contrib/ffmpeg/A08-mp4-faststart.patch @@ -0,0 +1,301 @@ +From 650a3dbf0cb6e38011bd6ea3ccec7148c7e9adb9 Mon Sep 17 00:00:00 2001 +From: John Stebbins <[email protected]> +Date: Fri, 10 May 2013 09:01:45 -0700 +Subject: [PATCH 5/9] movenc: allow placing moov atom at beginning of file + +Adds option to reserve space for moov. +--- + libavformat/movenc.c | 22 ++++++++++++++++++++-- + libavformat/movenc.h | 3 +++ + 2 files changed, 23 insertions(+), 2 deletions(-) + +diff --git a/libavformat/movenc.c b/libavformat/movenc.c +index f41f8d7..684f8d6 100644 +--- a/libavformat/movenc.c ++++ b/libavformat/movenc.c +@@ -51,6 +51,7 @@ static const AVOption options[] = { + { "separate_moof", "Write separate moof/mdat atoms for each track", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_SEPARATE_MOOF}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, + { "frag_custom", "Flush fragments on caller requests", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_CUSTOM}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, + { "isml", "Create a live smooth streaming feed (for pushing to a publishing point)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_ISML}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, ++ { "moov_size", "maximum moov size so it can be placed at the begin", offsetof(MOVMuxContext, reserved_moov_size), AV_OPT_TYPE_INT, {.dbl = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, 0 }, + FF_RTP_FLAG_OPTS(MOVMuxContext, rtp_flags), + { "skip_iods", "Skip writing iods atom.", offsetof(MOVMuxContext, iods_skip), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM}, + { "iods_audio_profile", "iods audio profile atom.", offsetof(MOVMuxContext, iods_audio_profile), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 255, AV_OPT_FLAG_ENCODING_PARAM}, +@@ -3146,8 +3147,13 @@ static int mov_write_header(AVFormatContext *s) + FF_MOV_FLAG_FRAGMENT; + } + +- if (!(mov->flags & FF_MOV_FLAG_FRAGMENT)) ++ if (!(mov->flags & FF_MOV_FLAG_FRAGMENT)) { ++ if(mov->reserved_moov_size) { ++ mov->reserved_moov_pos= avio_tell(pb); ++ avio_skip(pb, mov->reserved_moov_size); ++ } + mov_write_mdat_tag(pb, mov); ++ } + + if (t = av_dict_get(s->metadata, "creation_time", NULL, 0)) + mov->time = ff_iso8601_to_unix_time(t->value); +@@ -3219,9 +3225,21 @@ static int mov_write_trailer(AVFormatContext *s) + ffio_wfourcc(pb, "mdat"); + avio_wb64(pb, mov->mdat_size + 16); + } +- avio_seek(pb, moov_pos, SEEK_SET); ++ avio_seek(pb, mov->reserved_moov_size ? mov->reserved_moov_pos : moov_pos, SEEK_SET); + + mov_write_moov_tag(pb, mov, s); ++ if (mov->reserved_moov_size) { ++ int64_t size= mov->reserved_moov_size - (avio_tell(pb) - mov->reserved_moov_pos); ++ if(size < 8){ ++ av_log(s, AV_LOG_ERROR, "reserved_moov_size is too small, needed %"PRId64" additional\n", 8-size); ++ return -1; ++ } ++ avio_wb32(pb, size); ++ ffio_wfourcc(pb, "free"); ++ for(i=0; i<size; i++) ++ avio_w8(pb, 0); ++ avio_seek(pb, moov_pos, SEEK_SET); ++ } + } else { + mov_flush_fragment(s); + mov_write_mfra_tag(pb, mov); +diff --git a/libavformat/movenc.h b/libavformat/movenc.h +index e20ef14..f91fc5f 100644 +--- a/libavformat/movenc.h ++++ b/libavformat/movenc.h +@@ -153,6 +153,9 @@ typedef struct MOVMuxContext { + int max_fragment_size; + int ism_lookahead; + AVIOContext *mdat_buf; ++ ++ int reserved_moov_size; ++ int64_t reserved_moov_pos; + } MOVMuxContext; + + #define FF_MOV_FLAG_RTP_HINT 1 +-- +1.8.1.4 + +From 256ce14e2492ccdcb987afd6fb66ef590e58f02e Mon Sep 17 00:00:00 2001 +From: John Stebbins <[email protected]> +Date: Fri, 10 May 2013 09:11:32 -0700 +Subject: [PATCH 6/9] movenc: add faststart option for web streaming + +Faststart moves moov atom to beginning of file and rewrites the reset of +the file after muxing is complete. +--- + libavformat/movenc.c | 140 +++++++++++++++++++++++++++++++++++++++++++++++++-- + libavformat/movenc.h | 3 +- + 2 files changed, 137 insertions(+), 6 deletions(-) + +diff --git a/libavformat/movenc.c b/libavformat/movenc.c +index 684f8d6..7348cf8 100644 +--- a/libavformat/movenc.c ++++ b/libavformat/movenc.c +@@ -51,6 +51,7 @@ static const AVOption options[] = { + { "separate_moof", "Write separate moof/mdat atoms for each track", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_SEPARATE_MOOF}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, + { "frag_custom", "Flush fragments on caller requests", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_CUSTOM}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, + { "isml", "Create a live smooth streaming feed (for pushing to a publishing point)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_ISML}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, ++ { "faststart", "Run a second pass to put the moov at the beginning of the file", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FASTSTART}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, + { "moov_size", "maximum moov size so it can be placed at the begin", offsetof(MOVMuxContext, reserved_moov_size), AV_OPT_TYPE_INT, {.dbl = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, 0 }, + FF_RTP_FLAG_OPTS(MOVMuxContext, rtp_flags), + { "skip_iods", "Skip writing iods atom.", offsetof(MOVMuxContext, iods_skip), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM}, +@@ -3007,6 +3008,14 @@ static int mov_write_header(AVFormatContext *s) + FF_MOV_FLAG_FRAG_CUSTOM)) + mov->flags |= FF_MOV_FLAG_FRAGMENT; + ++ /* faststart: moov at the beginning of the file, if supported */ ++ if (mov->flags & FF_MOV_FLAG_FASTSTART) { ++ if (mov->flags & FF_MOV_FLAG_FRAGMENT) ++ mov->flags &= ~FF_MOV_FLAG_FASTSTART; ++ else ++ mov->reserved_moov_size = -1; ++ } ++ + /* Non-seekable output is ok if using fragmentation. If ism_lookahead + * is enabled, we don't support non-seekable output at all. */ + if (!s->pb->seekable && +@@ -3150,7 +3159,8 @@ static int mov_write_header(AVFormatContext *s) + if (!(mov->flags & FF_MOV_FLAG_FRAGMENT)) { + if(mov->reserved_moov_size) { + mov->reserved_moov_pos= avio_tell(pb); +- avio_skip(pb, mov->reserved_moov_size); ++ if(mov->reserved_moov_size > 0) ++ avio_skip(pb, mov->reserved_moov_size); + } + mov_write_mdat_tag(pb, mov); + } +@@ -3191,6 +3201,115 @@ static int mov_write_header(AVFormatContext *s) + return -1; + } + ++static int get_moov_size(AVFormatContext *s) ++{ ++ int ret; ++ uint8_t *buf; ++ AVIOContext *moov_buf; ++ MOVMuxContext *mov = s->priv_data; ++ ++ if ((ret = avio_open_dyn_buf(&moov_buf)) < 0) ++ return ret; ++ mov_write_moov_tag(moov_buf, mov, s); ++ ret = avio_close_dyn_buf(moov_buf, &buf); ++ av_free(buf); ++ return ret; ++} ++ ++/** ++ * This function gets the moov size if moved to the top of the file: the chunk ++ * offset table can switch between stco (32-bit entries) to co64 (64-bit ++ * entries) when the moov is moved to the top, so the size of the moov would ++ * change. It also updates the chunk offset tables. ++ */ ++static int compute_moov_size(AVFormatContext *s) ++{ ++ int i, moov_size, moov_size2; ++ MOVMuxContext *mov = s->priv_data; ++ ++ moov_size = get_moov_size(s); ++ if (moov_size < 0) ++ return moov_size; ++ ++ for (i = 0; i < mov->nb_streams; i++) ++ mov->tracks[i].data_offset += moov_size; ++ ++ moov_size2 = get_moov_size(s); ++ if (moov_size2 < 0) ++ return moov_size2; ++ ++ /* if the size changed, we just switched from stco to co64 and needs to ++ * update the offsets */ ++ if (moov_size2 != moov_size) ++ for (i = 0; i < mov->nb_streams; i++) ++ mov->tracks[i].data_offset += moov_size2 - moov_size; ++ ++ return moov_size2; ++} ++ ++static int shift_data(AVFormatContext *s) ++{ ++ int ret = 0, moov_size; ++ MOVMuxContext *mov = s->priv_data; ++ int64_t pos, pos_end = avio_tell(s->pb); ++ uint8_t *buf, *read_buf[2]; ++ int read_buf_id = 0; ++ int read_size[2]; ++ AVIOContext *read_pb; ++ ++ moov_size = compute_moov_size(s); ++ if (moov_size < 0) ++ return moov_size; ++ ++ buf = av_malloc(moov_size * 2); ++ if (!buf) ++ return AVERROR(ENOMEM); ++ read_buf[0] = buf; ++ read_buf[1] = buf + moov_size; ++ ++ /* Shift the data: the AVIO context of the output can only be used for ++ * writing, so we re-open the same output, but for reading. It also avoids ++ * a read/seek/write/seek back and forth. */ ++ avio_flush(s->pb); ++ ret = avio_open(&read_pb, s->filename, AVIO_FLAG_READ); ++ if (ret < 0) { ++ av_log(s, AV_LOG_ERROR, "Unable to re-open %s output file for " ++ "the second pass (faststart)\n", s->filename); ++ goto end; ++ } ++ ++ /* mark the end of the shift to up to the last data we wrote, and get ready ++ * for writing */ ++ pos_end = avio_tell(s->pb); ++ avio_seek(s->pb, mov->reserved_moov_pos + moov_size, SEEK_SET); ++ ++ /* start reading at where the new moov will be placed */ ++ avio_seek(read_pb, mov->reserved_moov_pos, SEEK_SET); ++ pos = avio_tell(read_pb); ++ ++#define READ_BLOCK do { \ ++ read_size[read_buf_id] = avio_read(read_pb, read_buf[read_buf_id], moov_size); \ ++ read_buf_id ^= 1; \ ++} while (0) ++ ++ /* shift data by chunk of at most moov_size */ ++ READ_BLOCK; ++ do { ++ int n; ++ READ_BLOCK; ++ n = read_size[read_buf_id]; ++ if (n <= 0) ++ break; ++ avio_write(s->pb, read_buf[read_buf_id], n); ++ pos += n; ++ } while (pos < pos_end); ++ avio_close(read_pb); ++ ++end: ++ av_free(buf); ++ return ret; ++} ++ + static int mov_write_trailer(AVFormatContext *s) + { + MOVMuxContext *mov = s->priv_data; +@@ -3225,11 +3344,20 @@ static int mov_write_trailer(AVFormatContext *s) + ffio_wfourcc(pb, "mdat"); + avio_wb64(pb, mov->mdat_size + 16); + } +- avio_seek(pb, mov->reserved_moov_size ? mov->reserved_moov_pos : moov_pos, SEEK_SET); + +- mov_write_moov_tag(pb, mov, s); +- if (mov->reserved_moov_size) { +- int64_t size= mov->reserved_moov_size - (avio_tell(pb) - mov->reserved_moov_pos); ++ avio_seek(pb, mov->reserved_moov_size > 0 ? mov->reserved_moov_pos : moov_pos, SEEK_SET); ++ ++ if (mov->reserved_moov_size == -1) { ++ av_log(s, AV_LOG_INFO, "Starting second pass: moving header on top of the file\n"); ++ res = shift_data(s); ++ if (res == 0) { ++ avio_seek(s->pb, mov->reserved_moov_pos, SEEK_SET); ++ mov_write_moov_tag(pb, mov, s); ++ } ++ } else if (mov->reserved_moov_size > 0) { ++ int64_t size; ++ mov_write_moov_tag(pb, mov, s); ++ size = mov->reserved_moov_size - (avio_tell(pb) - mov->reserved_moov_pos); + if(size < 8){ + av_log(s, AV_LOG_ERROR, "reserved_moov_size is too small, needed %"PRId64" additional\n", 8-size); + return -1; +@@ -3239,6 +3367,8 @@ static int mov_write_trailer(AVFormatContext *s) + for(i=0; i<size; i++) + avio_w8(pb, 0); + avio_seek(pb, moov_pos, SEEK_SET); ++ } else { ++ mov_write_moov_tag(pb, mov, s); + } + } else { + mov_flush_fragment(s); +diff --git a/libavformat/movenc.h b/libavformat/movenc.h +index f91fc5f..3ea0dd5 100644 +--- a/libavformat/movenc.h ++++ b/libavformat/movenc.h +@@ -154,7 +154,7 @@ typedef struct MOVMuxContext { + int ism_lookahead; + AVIOContext *mdat_buf; + +- int reserved_moov_size; ++ int reserved_moov_size; ///< 0 for disabled, -1 for automatic, size otherwise + int64_t reserved_moov_pos; + } MOVMuxContext; + +@@ -165,6 +165,7 @@ typedef struct MOVMuxContext { + #define FF_MOV_FLAG_SEPARATE_MOOF 16 + #define FF_MOV_FLAG_FRAG_CUSTOM 32 + #define FF_MOV_FLAG_ISML 64 ++#define FF_MOV_FLAG_FASTSTART 128 + + int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt); + +-- +1.8.1.4 + diff --git a/contrib/ffmpeg/A09-mp4-64bit.patch b/contrib/ffmpeg/A09-mp4-64bit.patch new file mode 100644 index 000000000..04fec6032 --- /dev/null +++ b/contrib/ffmpeg/A09-mp4-64bit.patch @@ -0,0 +1,46 @@ +From 68f89a1ec9ccef22268158640c1f62f0370f48ba Mon Sep 17 00:00:00 2001 +From: John Stebbins <[email protected]> +Date: Fri, 10 May 2013 09:12:54 -0700 +Subject: [PATCH 7/9] movenc: fix detection of 64bit offset requirement + +The old method doesn't work when moov is relocated to beginning of file +--- + libavformat/movenc.c | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +diff --git a/libavformat/movenc.c b/libavformat/movenc.c +index 7348cf8..2f6c003 100644 +--- a/libavformat/movenc.c ++++ b/libavformat/movenc.c +@@ -83,15 +83,25 @@ static int64_t update_size(AVIOContext *pb, int64_t pos) + return curpos - pos; + } + ++static int is_co64_required(const MOVTrack *track) ++{ ++ int i; ++ ++ for (i = 0; i < track->entry; i++) { ++ if (track->cluster[i].pos + track->data_offset > UINT32_MAX) ++ return 1; ++ } ++ return 0; ++} ++ + /* Chunk offset atom */ + static int mov_write_stco_tag(AVIOContext *pb, MOVTrack *track) + { + int i; +- int mode64 = 0; // use 32 bit size variant if possible ++ int mode64 = is_co64_required(track); // use 32 bit size variant if possible + int64_t pos = avio_tell(pb); + avio_wb32(pb, 0); /* size */ +- if (pos > UINT32_MAX) { +- mode64 = 1; ++ if (mode64) { + ffio_wfourcc(pb, "co64"); + } else + ffio_wfourcc(pb, "stco"); +-- +1.8.1.4 + diff --git a/contrib/ffmpeg/A10-mp4-track-enable.patch b/contrib/ffmpeg/A10-mp4-track-enable.patch new file mode 100644 index 000000000..282326157 --- /dev/null +++ b/contrib/ffmpeg/A10-mp4-track-enable.patch @@ -0,0 +1,142 @@ +From 25a0ee27bb5d2bb46781ea4a2a3c88581ad75fde Mon Sep 17 00:00:00 2001 +From: John Stebbins <[email protected]> +Date: Fri, 10 May 2013 09:16:08 -0700 +Subject: [PATCH 8/9] movenc: Make tkhd "enabled" flag QuickTime compatible + +QuickTime will play multiple audio tracks concurrently if this flag is +set for multiple audio tracks. And if no subtitle track has this flag +set QuickTime will show no subtitles in the subtitle menu. +--- + libavformat/mov.c | 4 +++- + libavformat/movenc.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++- + libavformat/movenc.h | 1 + + 3 files changed, 63 insertions(+), 2 deletions(-) + +diff --git a/libavformat/mov.c b/libavformat/mov.c +index 7fe0548..cb0e395 100644 +--- a/libavformat/mov.c ++++ b/libavformat/mov.c +@@ -2129,6 +2129,7 @@ static int mov_read_tkhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) + AVStream *st; + MOVStreamContext *sc; + int version; ++ int flags; + + if (c->fc->nb_streams < 1) + return 0; +@@ -2136,13 +2137,14 @@ static int mov_read_tkhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) + sc = st->priv_data; + + version = avio_r8(pb); +- avio_rb24(pb); /* flags */ ++ flags = avio_rb24(pb); /* flags */ + /* + MOV_TRACK_ENABLED 0x0001 + MOV_TRACK_IN_MOVIE 0x0002 + MOV_TRACK_IN_PREVIEW 0x0004 + MOV_TRACK_IN_POSTER 0x0008 + */ ++ st->disposition |= (flags & 0x1) ? AV_DISPOSITION_DEFAULT : 0; + + if (version == 1) { + avio_rb64(pb); +diff --git a/libavformat/movenc.c b/libavformat/movenc.c +index 2f6c003..bc77a6f 100644 +--- a/libavformat/movenc.c ++++ b/libavformat/movenc.c +@@ -1387,7 +1387,13 @@ static int mov_write_tkhd_tag(AVIOContext *pb, MOVTrack *track, AVStream *st) + (version == 1) ? avio_wb32(pb, 104) : avio_wb32(pb, 92); /* size */ + ffio_wfourcc(pb, "tkhd"); + avio_w8(pb, version); +- avio_wb24(pb, 0xf); /* flags (track enabled) */ ++ avio_wb24(pb, (track->flags & MOV_TRACK_ENABLED) ? 0x3 : 0x2); /* flags */ ++ /* ++ MOV_TRACK_ENABLED 0x0001 ++ MOV_TRACK_IN_MOVIE 0x0002 ++ MOV_TRACK_IN_PREVIEW 0x0004 ++ MOV_TRACK_IN_POSTER 0x0008 ++ */ + if (version == 1) { + avio_wb64(pb, track->time); + avio_wb64(pb, track->time); +@@ -3003,6 +3009,56 @@ static void mov_create_chapter_track(AVFormatContext *s, int tracknum) + } + } + ++// st->disposition controls the "enabled" flag in the tkhd tag. ++// QuickTime will not play a track if it is not enabled. So make sure ++// that one track of each type (audio, video, subtitle) is enabled. ++// ++// Subtitles are special. For audio and video, setting "enabled" also ++// makes the track "default" (i.e. it is rendered when played). For ++// subtitles, an "enabled" subtitle is not rendered by default, but ++// if no subtitle is enabled, the subtitle menu in QuickTime will be ++// empty! ++static void enable_tracks(AVFormatContext *s) ++{ ++ MOVMuxContext *mov = s->priv_data; ++ int i; ++ uint8_t enabled[AVMEDIA_TYPE_NB]; ++ int first[AVMEDIA_TYPE_NB]; ++ ++ for (i = 0; i < AVMEDIA_TYPE_NB; i++) { ++ enabled[i] = 0; ++ first[i] = -1; ++ } ++ ++ for (i = 0; i < s->nb_streams; i++) { ++ AVStream *st = s->streams[i]; ++ ++ if (st->codec->codec_type <= AVMEDIA_TYPE_UNKNOWN || ++ st->codec->codec_type >= AVMEDIA_TYPE_NB) ++ continue; ++ ++ if (first[st->codec->codec_type] < 0) ++ first[st->codec->codec_type] = i; ++ if (st->disposition & AV_DISPOSITION_DEFAULT) { ++ mov->tracks[i].flags |= MOV_TRACK_ENABLED; ++ enabled[st->codec->codec_type] = 1; ++ } ++ } ++ ++ for (i = 0; i < AVMEDIA_TYPE_NB; i++) { ++ switch (i) { ++ case AVMEDIA_TYPE_VIDEO: ++ case AVMEDIA_TYPE_AUDIO: ++ case AVMEDIA_TYPE_SUBTITLE: ++ if (!enabled[i] && first[i] >= 0) ++ mov->tracks[first[i]].flags |= MOV_TRACK_ENABLED; ++ break; ++ default: ++ break; ++ } ++ } ++} ++ + static int mov_write_header(AVFormatContext *s) + { + AVIOContext *pb = s->pb; +@@ -3156,6 +3212,8 @@ static int mov_write_header(AVFormatContext *s) + } + } + ++ enable_tracks(s); ++ + if (mov->mode == MODE_ISM) { + /* If no fragmentation options have been set, set a default. */ + if (!(mov->flags & (FF_MOV_FLAG_FRAG_KEYFRAME | +diff --git a/libavformat/movenc.h b/libavformat/movenc.h +index 3ea0dd5..9bb8a78 100644 +--- a/libavformat/movenc.h ++++ b/libavformat/movenc.h +@@ -84,6 +84,7 @@ typedef struct MOVIndex { + int has_keyframes; + #define MOV_TRACK_CTTS 0x0001 + #define MOV_TRACK_STPS 0x0002 ++#define MOV_TRACK_ENABLED 0x0004 + uint32_t flags; + int language; + int track_id; +-- +1.8.1.4 + diff --git a/contrib/ffmpeg/A11-mp4-chapter-properties.patch b/contrib/ffmpeg/A11-mp4-chapter-properties.patch new file mode 100644 index 000000000..9f64af2cb --- /dev/null +++ b/contrib/ffmpeg/A11-mp4-chapter-properties.patch @@ -0,0 +1,47 @@ +From 9393762b54c17abd736f8d5dd96cd22c334989da Mon Sep 17 00:00:00 2001 +From: John Stebbins <[email protected]> +Date: Fri, 10 May 2013 09:19:16 -0700 +Subject: [PATCH 9/9] movenc: Make chapter track QuickTime compatible + +QuickTime requires that the stsd.text box be completely filled in. +--- + libavformat/movenc.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/libavformat/movenc.c b/libavformat/movenc.c +index bc77a6f..96adfd7 100644 +--- a/libavformat/movenc.c ++++ b/libavformat/movenc.c +@@ -2982,12 +2982,17 @@ static void mov_create_chapter_track(AVFormatContext *s, int tracknum) + MOVTrack *track = &mov->tracks[tracknum]; + AVPacket pkt = { .stream_index = tracknum, .flags = AV_PKT_FLAG_KEY }; + int i, len; ++ // These properties are required to make QT recognize the chapter track ++ uint8_t chapter_properties[43] = {0, 0, 0, 0, 0, 0, 0, 1,}; + + track->mode = mov->mode; + track->tag = MKTAG('t','e','x','t'); + track->timescale = MOV_TIMESCALE; + track->enc = avcodec_alloc_context3(NULL); + track->enc->codec_type = AVMEDIA_TYPE_SUBTITLE; ++ track->enc->extradata = av_malloc(43); ++ track->enc->extradata_size = 43; ++ memcpy(track->enc->extradata, chapter_properties, 43); + + for (i = 0; i < s->nb_chapters; i++) { + AVChapter *c = s->chapters[i]; +@@ -3443,8 +3448,10 @@ static int mov_write_trailer(AVFormatContext *s) + mov_write_mfra_tag(pb, mov); + } + +- if (mov->chapter_track) ++ if (mov->chapter_track) { ++ av_free(mov->tracks[mov->chapter_track].enc->extradata); + av_freep(&mov->tracks[mov->chapter_track].enc); ++ } + + for (i=0; i<mov->nb_streams; i++) { + if (mov->tracks[i].tag == MKTAG('r','t','p',' ')) +-- +1.8.1.4 + diff --git a/contrib/ffmpeg/module.defs b/contrib/ffmpeg/module.defs index 70982af11..34469582d 100644 --- a/contrib/ffmpeg/module.defs +++ b/contrib/ffmpeg/module.defs @@ -1,4 +1,8 @@ +ifeq (1,$(FEATURE.qsv)) +$(eval $(call import.MODULE.defs,FFMPEG,ffmpeg,YASM BZIP2 ZLIB FDKAAC PTHREADW32 LIBMFX)) +else $(eval $(call import.MODULE.defs,FFMPEG,ffmpeg,YASM BZIP2 ZLIB FDKAAC)) +endif $(eval $(call import.CONTRIB.defs,FFMPEG)) FFMPEG.FETCH.url = http://download.handbrake.fr/handbrake/contrib/libav-v9.6.tar.bz2 @@ -26,7 +30,6 @@ FFMPEG.CONFIGURE.extra = \ --enable-encoder=flac \ --enable-encoder=mpeg2video \ --enable-encoder=mpeg4 \ - --enable-encoder=snow \ --enable-zlib \ --enable-bzlib \ --cc="$(FFMPEG.GCC.gcc)" \ @@ -39,6 +42,16 @@ FFMPEG.CONFIGURE.extra += \ --enable-encoder=libfdk_aac endif +ifeq (1,$(FEATURE.avformat)) +FFMPEG.CONFIGURE.extra += \ + --enable-muxer=matroska \ + --enable-muxer=webm \ + --enable-muxer=mov \ + --enable-muxer=mp4 \ + --enable-muxer=psp \ + --enable-muxer=ipod +endif + ## check against tuple: B-SYSTEM where B is { 0 | 1 } for cross-compiling flag ifeq (0-cygwin,$(BUILD.cross)-$(BUILD.system)) FFMPEG.CONFIGURE.extra += --enable-pthreads --enable-memalign-hack @@ -81,6 +94,10 @@ ifeq (none,$(FFMPEG.GCC.O)) FFMPEG.CONFIGURE.extra += --disable-optimizations endif +ifeq (1,$(FEATURE.qsv)) + FFMPEG.CONFIGURE.extra += --enable-qsv +endif + ## enable compile verbosity FFMPEG.BUILD.extra = V=1 diff --git a/contrib/libmfx/module.defs b/contrib/libmfx/module.defs new file mode 100644 index 000000000..4377123b9 --- /dev/null +++ b/contrib/libmfx/module.defs @@ -0,0 +1,6 @@ +$(eval $(call import.MODULE.defs,LIBMFX,libmfx)) +$(eval $(call import.CONTRIB.defs,LIBMFX)) + +LIBMFX.FETCH.url = http://download.handbrake.fr/contrib/libmfx_intel_msdk_2013r2.tar.bz2 + +LIBMFX.CONFIGURE.bootstrap = rm -fr aclocal.m4 autom4te.cache; autoreconf -fiv; diff --git a/contrib/libmfx/module.rules b/contrib/libmfx/module.rules new file mode 100644 index 000000000..ffa581f04 --- /dev/null +++ b/contrib/libmfx/module.rules @@ -0,0 +1,2 @@ +$(eval $(call import.MODULE.rules,LIBMFX)) +$(eval $(call import.CONTRIB.rules,LIBMFX)) diff --git a/contrib/x264/A00-version-string.patch b/contrib/x264/A00-version-string.patch index dcd4ec628..6610bd1a6 100644 --- a/contrib/x264/A00-version-string.patch +++ b/contrib/x264/A00-version-string.patch @@ -1,12 +1,12 @@ diff --git a/x264.h b/x264.h -index e5a1600..f635d9e 100644 +index b88f510..7dd0891 100644 --- a/x264.h +++ b/x264.h @@ -41,7 +41,17 @@ #include "x264_config.h" --#define X264_BUILD 130 +-#define X264_BUILD 135 +/* + * Define the full version explicitly so that it survives a git --archive. + * @@ -16,8 +16,8 @@ index e5a1600..f635d9e 100644 +#ifdef X264_VERSION +#undef X264_VERSION +#endif -+#define X264_BUILD 130 -+#define X264_VERSION " r2273 b3065e6" ++#define X264_BUILD 135 ++#define X264_VERSION " r2345 f0c1c53" /* Application developers planning to link against a shared library version of * libx264 from a Microsoft Visual Studio or similar development environment diff --git a/contrib/x264/module.defs b/contrib/x264/module.defs index 097f88d42..876dc6462 100644 --- a/contrib/x264/module.defs +++ b/contrib/x264/module.defs @@ -1,15 +1,14 @@ $(eval $(call import.MODULE.defs,X264,x264,YASM PTHREADW32)) $(eval $(call import.CONTRIB.defs,X264)) -X264.FETCH.url = http://download.handbrake.fr/handbrake/contrib/x264-r2273-b3065e6.tar.gz +X264.FETCH.url = http://download.handbrake.fr/handbrake/contrib/x264-r2345-f0c1c53.tar.gz X264.EXTRACT.tarbase = x264 X264.CONFIGURE.deps = X264.CONFIGURE.shared = -X264.CONFIGURE.static = -X264.CONFIGURE.extra = --disable-cli --enable-static --enable-strip -X264.CONFIGURE.extra += --disable-gpac --disable-avs --disable-lavf --disable-ffms --disable-swscale +X264.CONFIGURE.extra = --enable-strip --bit-depth=8 --chroma-format=420 +X264.CONFIGURE.extra += --disable-lavf --disable-ffms --disable-avs --disable-swscale --disable-gpac --disable-cli ifeq (1-mingw,$(BUILD.cross)-$(BUILD.system)) X264.CONFIGURE.extra += --cross-prefix=$(BUILD.spec)- diff --git a/gtk/configure.ac b/gtk/configure.ac index 6d013f935..88b77ef8b 100644 --- a/gtk/configure.ac +++ b/gtk/configure.ac @@ -60,6 +60,18 @@ AC_ARG_ENABLE(fdk-aac, AS_HELP_STRING([--enable-fdk-aac], [enable fdk aac encoder]), use_fdk_aac=yes, use_fdk_aac=no) +AC_ARG_ENABLE(faac, + AS_HELP_STRING([--enable-faac], [enable faac encoder]), + use_faac=yes, use_faac=no) + +AC_ARG_ENABLE(mp4v2, + AS_HELP_STRING([--enable-mp4v2], [enable mp4v2 muxer]), + use_mp4v2=yes, use_mp4v2=no) + +AC_ARG_ENABLE(libmkv, + AS_HELP_STRING([--enable-libmkv], [enable libmkv muxer]), + use_libmkv=yes, use_libmkv=no) + AC_ARG_ENABLE(gst, AS_HELP_STRING([--disable-gst], [disable gstreamer (live preview)]), gst_disable=yes, gst_disable=no) @@ -203,12 +215,24 @@ case $host in ;; esac -HB_LIBS="-lhb -la52 -lmkv -lavresample -lavformat -lavcodec -lavutil -ldvdnav -ldvdread -lfaac -lmp3lame -lmpeg2 -lvorbis -lvorbisenc -logg -lsamplerate -lx264 -lmp4v2 -lswscale -ltheoraenc -ltheoradec -lz -lbz2 -lpthread -lbluray -lass -lfontconfig -lfreetype -lxml2" +HB_LIBS="-lhb -la52 -lavresample -lavformat -lavcodec -lavutil -ldvdnav -ldvdread -lmp3lame -lmpeg2 -lvorbis -lvorbisenc -logg -lsamplerate -lx264 -lswscale -ltheoraenc -ltheoradec -lz -lbz2 -lpthread -lbluray -lass -lfontconfig -lfreetype -lxml2" if test "x$use_fdk_aac" = "xyes" ; then HB_LIBS+=" -lfdk-aac" fi +if test "x$use_faac" = "xyes" ; then + HB_LIBS+=" -lfaac" +fi + +if test "x$use_mp4v2" = "xyes" ; then + HB_LIBS+=" -lmp4v2" +fi + +if test "x$use_libmkv" = "xyes" ; then + HB_LIBS+=" -lmkv" +fi + AC_SUBST(HB_LIBS) AC_SUBST(GHB_TOOLS_CFLAGS) AC_SUBST(GHB_TOOLS_LIBS) diff --git a/gtk/ghb.spec b/gtk/ghb.spec index e4a65922a..1806fac18 100644 --- a/gtk/ghb.spec +++ b/gtk/ghb.spec @@ -49,6 +49,7 @@ make %{?_smp_mflags} -C build %install make -C build DESTDIR=$RPM_BUILD_ROOT install-strip +%find_lang ghb ## blow away stuff we don't want /bin/rm -f $RPM_BUILD_ROOT%{_datadir}/icons/hicolor/icon-theme.cache @@ -68,7 +69,7 @@ if [ -x /usr/bin/gtk-update-icon-cache ]; then gtk-update-icon-cache -q %{_datadir}/icons/hicolor fi -%files gui +%files gui -f ghb.lang %defattr(-,root,root,-) %doc NEWS AUTHORS CREDITS THANKS COPYING %{_datadir}/icons/hicolor diff --git a/gtk/module.defs b/gtk/module.defs index 8eddc6d91..bafca356d 100644 --- a/gtk/module.defs +++ b/gtk/module.defs @@ -32,3 +32,15 @@ endif ifeq (1,$(FEATURE.fdk_aac)) GTK.CONFIGURE.extra += --enable-fdk-aac endif + +ifeq (1,$(FEATURE.faac)) + GTK.CONFIGURE.extra += --enable-faac +endif + +ifeq (1,$(FEATURE.mp4v2)) + GTK.CONFIGURE.extra += --enable-mp4v2 +endif + +ifeq (1,$(FEATURE.libmkv)) + GTK.CONFIGURE.extra += --enable-libmkv +endif diff --git a/gtk/po/LINGUAS b/gtk/po/LINGUAS index bc8cbb0fe..0c1544ebc 100644 --- a/gtk/po/LINGUAS +++ b/gtk/po/LINGUAS @@ -1,2 +1,3 @@ # please keep this list sorted alphabetically # +ru diff --git a/gtk/po/POTFILES.in b/gtk/po/POTFILES.in index a0b3c552e..226421484 100644 --- a/gtk/po/POTFILES.in +++ b/gtk/po/POTFILES.in @@ -1,3 +1,3 @@ # List of source files containing translatable strings. - src/main.c +src/ghb.ui diff --git a/gtk/po/ru.po b/gtk/po/ru.po new file mode 100644 index 000000000..fa35e0581 --- /dev/null +++ b/gtk/po/ru.po @@ -0,0 +1,1696 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Victor Ryzhykh <[email protected]>, 2013. +msgid "" +msgstr "" +"Project-Id-Version: handbrake\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-07-13 12:44+0400\n" +"PO-Revision-Date: 2013-07-26 15:32+0300\n" +"Last-Translator: \n" +"Language-Team: Russian <[email protected]>\n" +"Language: ru\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n" +"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;'nX-Generator: Lokalize " +"1.5\n" +"X-Generator: Lokalize 1.5\n" + +#: rc.cpp:1 +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Виктор Рыжих" + +#: rc.cpp:2 +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "[email protected]" + +msgid "File:" +msgstr "Файл:" + +msgid "_File" +msgstr "_Файл" + +msgid "_Queue" +msgstr "_Очередь" + +msgid "_View" +msgstr "_Вид" + +msgid "Format:" +msgstr "Формат:" + +msgid "<b>Source:</b>" +msgstr "<b>Источник:</b>" + +msgid "_Source" +msgstr "_Добавить папку" + +msgid "Single _Title" +msgstr "Выбрать _файл" + +msgid "_Destination" +msgstr "_Файл выхода" + +msgid "_Make Default" +msgstr "_Сделать по умолчанию" + +msgid "Start Encoding" +msgstr "Начать кодирование" + +msgid "_Start Encoding" +msgstr "_Начать кодирование" + +msgid "_Pause Encoding" +msgstr "_Приостановить кодирование" + +msgid "Pause Encoding" +msgstr "Приостановить кодирование" + +msgid "_Stop Encoding" +msgstr "_Остановить кодирование" + +msgid "Stop Encoding" +msgstr "Остановить кодирование" + +msgid "_Resume Encoding" +msgstr "_Продолжить кодирование" + +msgid "Resume Encoding" +msgstr "Продолжить кодирование" + +msgid "Add Queue" +msgstr "Добавить в очередь" + +msgid "_Add Queue" +msgstr "_Добавить в очередь" + +msgid "Add A_ll Queue" +msgstr "Добавить в_се в очередь" + +msgid "_Start Queue" +msgstr "_Начать очередь" + +msgid "Start Queue" +msgstr "Начать очередь" + +msgid "_Pause Queue" +msgstr "_Приостановить очередь" + +msgid "Pause Queue" +msgstr "Приостановить очередь" + +msgid "_Resume Queue" +msgstr "_Продолжить очередь" + +msgid "Resume Queue" +msgstr "Продолжить очередь" + +msgid "_Stop Queue" +msgstr "_Остановить очередь" + +msgid "S_top Queue" +msgstr "О_становить очередь" + +msgid "Stop Queue" +msgstr "Остановить очередь" + +msgid "None" +msgstr "Нет" + +msgid "<b>Picture:</b> Source: <small>%d x %d, Output %d x %d %s</small>\n" +msgstr "" +"<b>Изображение</b> Источник: <small>%d x %d, Вывод %d x %d %s</small>\n" + +msgid "No Titles" +msgstr "Без названия" + +msgid "hh:mm:ss" +msgstr "чч:мм:сс" + +msgid "HandBrake For _Dumbies" +msgstr "" + +msgid "Show Presets" +msgstr "Показать предустановки" + +msgid "_Picture Settings" +msgstr "_Настройка изображения" + +msgid "_Activity Window" +msgstr "_Окно процесса обработки" + +msgid "Show _Queue" +msgstr "Показать _очередь" + +msgid "_Help" +msgstr "_Помощь" + +msgid "_Guide" +msgstr "_Руководство" + +msgid "_Minimize/Maximize" +msgstr "_Свернуть/распахнуть" + +msgid "New _Folder" +msgstr "Создать _папку" + +msgid "_Export" +msgstr "_Экспорт" + +msgid "_Import" +msgstr "_Импорт" + +msgid "_Update Built-in Presets" +msgstr "_Обновить предустановки" + +msgid "Choose Video Source" +msgstr "Выбрать исходное видео" + +msgid "Add to Queue" +msgstr "Добавить в очередь" + +msgid "Enqueue" +msgstr "Очерёдность" + +msgid "Show Queue" +msgstr "Показать очередь" + +msgid "Queue" +msgstr "Очередь" + +msgid "" +"Open Picture Settings and Preview window. Here you can adjust cropping, " +"resolution, aspect ratio, and filters." +msgstr "" +"Открыть настройки изображения и окно просмотра. Здесь вы можете " +"отрегулировать обрезку, разрешение, соотношение сторон и фильтры." + +msgid "Picture Settings" +msgstr "Настройка изображения" + +msgid "Show Activity Window" +msgstr "Показать окно процесса обработки" + +msgid "Activity" +msgstr "Активность" + +msgid "" +"Set the title to encode. By default the longest title is chosen. This is " +"often the feature title of a DVD." +msgstr "" +"Установить заголовок для кодирования. По умолчанию выбрано длинное " +"название. Часто это заголовок функций DVD." + +msgid "Angle:" +msgstr "Угол:" + +msgid "For multi-angle DVD's, select the desired angle to encode." +msgstr "Для нескольких ракурсов DVD, выберите нужный ракурс для кодирования." + +msgid "Range of title to encode. Can be chapters, seconds, or frames." +msgstr "" +"Диапазон заглавий для кодирования. Могут быть главы, секунды или кадры." + +msgid "" +"The source subtitle track\n" +"\n" +"You can choose any of the subtitles\n" +"recognized in your source file.\n" +"\n" +"In addition, there is a special track option\n" +"\"Foreign Audio Search\". This option will add\n" +"an extra pass to the encode that searches for\n" +"subtitles that may correspond to a foreign\n" +"language scene. This option is best used in\n" +"conjunction with the \"Forced\" option." +msgstr "" + +msgid "<b>Track</b>" +msgstr "<b>Дорожка</b>" + +msgid "<b>Forced Only</b>" +msgstr "<b>Только встроенные</b>" + +msgid "" +"Use only subtitles that have been flagged\n" +"as forced in the source subtitle track\n" +"\n" +"\"Forced\" subtitles are usually used to show\n" +"subtitles during scenes where someone is speaking\n" +"a foreign language.\n" +msgstr "" + +msgid "<b>Burned In</b>" +msgstr "<b>Встроенные</b>" + +msgid "" +"Render the subtitle over the video.\n" +"\n" +"The subtitle will be part of the video and can not be disabled." +msgstr "" +"Отображение субтитров на видео.\n" +"\n" +"Субтитры будут на части видео и не могут быть отключены." + +msgid "<b>Default</b>" +msgstr "<b>По умолчанию</b>" + +msgid "" +"Set the default output subtitle track.\n" +"\n" +"Most players will automatically display this\n" +"subtitle track whenever the video is played.\n" +"\n" +"This is usefule for creating a \"forced\" track\n" +"in your output." +msgstr "" + +msgid "<b>SRT Offset</b>" +msgstr "<b>Смещение SRT</b>" + +msgid "" +"Add (or subtract) an offset (in milliseconds)\n" +"to the start of the SRT subtitle track.\n" +"\n" +"Often, the start of an external SRT file\n" +"does not coincide with the start of the video.\n" +"This setting allows you to synchronize the files." +msgstr "" + +msgid "Set the first chapter to encode." +msgstr "Установить первую главу для кодирования." + +msgid "through" +msgstr "по" + +msgid "Set the last chapter to encode." +msgstr "Установить последнюю главу для кодирования." + +msgid "Duration:" +msgstr "Продолжительность:" + +msgid "Destination Directory" +msgstr "Каталог назначения" + +msgid "Destination directory for your encode." +msgstr "Папка назначения для перекодированных файлов." + +msgid "Destination filename for your encode." +msgstr "Название папки для перекодированных файлов." + +msgid "Format to mux encoded tracks to." +msgstr "Формат мультиплексора кодирования треков." + +msgid "iPod 5G Support" +msgstr "Поддержка iPod 5G" + +msgid "Add iPod Atom needed by some older iPods." +msgstr "Добавить iPod Atom, необходимый некоторым старым плеерам." + +msgid "Web optimized" +msgstr "Веб оптимизация" + +msgid "" +"Optimize the layout of the MP4 file for progressive download. This allows a " +"player to initiate playback before downloading the entire file." +msgstr "" +"Оптимизировать структуру файлов MP4 для последовательной загрузки. Это " +"позволяет проигрывателю начать воспроизведение до загрузки всего файла." + +msgid "Large file (>4GB)" +msgstr "Большой файл (>4GB)" + +msgid "" +"Allow 64 bit MP4 file which can be over 4GB.\n" +"\n" +" <b>Caution:</b> This option may break device compatibility." +msgstr "" +"Разрешить 64 битный MP4 файл, который может быть более 4 ГБ.\n" +"\n" +" <b>Внимание:</b> Эта опция может сломать совместимость устройств." + +msgid "<b><u>D</u>estination</b>" +msgstr "<b><u>Н</u>азначение</b>" + +msgid "Source Codec:" +msgstr "Кодек источника:" + +msgid "Dimensions:" +msgstr "Размер:" + +msgid "Aspect: " +msgstr "Соотношение сторон: " + +msgid "Frame Rate:" +msgstr "Частота кадров:" + +msgid "<b>Source Picture Parameters</b>" +msgstr "<b>Параметры картинки источника</b>" + +msgid "Autocrop:" +msgstr "Автокадрирование:" + +msgid "On" +msgstr "Вкл" + +msgid "Crop:" +msgstr "Кадрирование:" + +msgid "Scale Dimensions:" +msgstr "Масштаб:" + +msgid "Optimal for Source:" +msgstr "Оптимально для источника:" + +msgid "Off" +msgstr "Вкл" + +msgid "Anamorphic:" +msgstr "Анаморфотный:" + +msgid "<b>Scaling</b>" +msgstr "<b>Масштабирование</b>" + +msgid "Presentation Dimensions:" +msgstr "Размеры презентации:" + +msgid "Summary" +msgstr "Описание" + +msgid "Video Encoder:" +msgstr "Видео кодеки:" + +msgid "Available video encoders." +msgstr "Доступные видео кодеки." + +msgid "Framerate:" +msgstr "Частота кадров:" + +msgid "" +"Output framerate. 'Same as source' is recommended. If your source video has " +"a variable framerate, 'Same as source' will preserve it." +msgstr "" +"Частота кадров на выходе. Рекомендуется 'Так же, как в источнике'. Если " +"исходное видео имеет переменную частоту кадров, выбор 'Так же, как в " +"источнике' сохранит ее." + +msgid "Constant Framerate" +msgstr "Постоянная частота кадров" + +msgid "" +"Enables variable framerate output with a peak rate determined by the " +"framerate setting. VFR is not compatible with some players." +msgstr "" +"Включает переменную частоту кадров на выходе с пиковой скоростью, " +"определенной настройкой частоты кадров. VFR не совместим с некоторыми " +"проигрывателями." + +msgid "Peak Framerate (VFR)" +msgstr "Пик частоты кадров (VFR)" + +msgid "" +"Enables variable framerate output. VFR is not compatible with some players." +msgstr "" +"Включает переменную частоту кадров на выходе. VFR не совместим с некоторыми " +"проигрывателями." + +msgid "Variable Framerate" +msgstr "Переменная частота кадров" + +msgid "" +"Set the desired quality factor. The encoder targets a certain quality. The " +"scale used by each video encoder is different. \n" +"\n" +" x264's scale is logarithmic and lower values coorespond to " +"higher quality. So small decreases in value will result in progressively " +"larger increases in the resulting file size. A value of 0 means lossless " +"and will result in a file size that is larger than the original source, " +"unless the source was also lossless.\n" +"\n" +" FFMpeg's and Theora's scale is more linear. These encoders do " +"not have a lossless mode." +msgstr "" + +msgid "Constant Quality:" +msgstr "Постоянное качество:" + +msgid "" +"Set the average bitrate. The instantaneous bitrate can be much higher or " +"lower at any point in time. But the average over a long duration will be " +"the value set here. If you need to limit instantaneous bitrate, look into " +"x264's vbv-bufsize and vbv-maxrate settings." +msgstr "" + +msgid "Bitrate (kbps): " +msgstr "Битрейт (кбит/с): " + +msgid "" +"Set the average bitrate. The instantaneous bitrate can be much higher or " +"lower at any point in time. But the average over a long duration will be " +"the value set here. If you need to limit instantaneous bitrate, look into " +"x264 vbv-bufsize and vbv-maxrate." +msgstr "" + +msgid "" +"Perform 2 Pass Encoding. The 'Bitrate' option is prerequisite. During the " +"1st pass, statistics about the video are collected. Then in the second " +"pass, those statistics are used to make bitrate allocation decisions." +msgstr "" + +msgid "2-Pass Encoding" +msgstr "Кодировка в 2-прохода" + +msgid "" +"During the 1st pass of a 2 pass encode, use settings that speed things along." +msgstr "" +"Во время 1-го проход при 2-х проходном кодировании используйте настройки " +"скоростного прохода." + +msgid "Turbo First Pass" +msgstr "Первый проход турбо" + +msgid "" +"Use advanced options Tab for x264 settings.\n" +"\n" +" Use at your own risk!" +msgstr "" +"Используйте вкладку дополнительных настроек для настройки x264. \n" +"\n" +" Используйте на свой страх и риск!" + +msgid "Use Advanced Options" +msgstr "Использовать дополнительные параметры" + +msgid "x264 Preset:" +msgstr "Предустановки x264:" + +msgid "" +"Adjusts x264 settings to trade off compression efficiency against encoding " +"speed.\n" +"\n" +" This establishes your default x264 settings. Tunes, profiles, " +"levels and advanced option string will be applied to this.\n" +"\n" +" You should generally set this option to the slowest you can bear " +"since slower settings will result in better quality or smaller files." +msgstr "" + +msgid "x264 Tune:" +msgstr "Настройки x264 :" + +msgid "" +"Tune settings to optimize for common scenarios.\n" +"\n" +" This can improve effeciency for particular source " +"characteristics or set characteristics of the output file.\n" +"\n" +" Changes will be applied after the preset but before all other " +"parameters." +msgstr "" +"Настройки параметров оптимизированных для выполнения типовых сценариев.\n" +"\n" +" Это может улучшить содержание для конкретных характеристик " +"исходного или заданных характеристик выходного файла.\n" +"\n" +" Изменения вступят в силу по завершении установленных заранее, но " +"перед всеми другими параметрами." + +msgid "" +"Reduce decoder CPU usage.\n" +"\n" +" Set this if your device is struggling to play the output " +"(dropped frames)." +msgstr "" +"Уменьшает использование CPU при декодировании.\n" +"\n" +" Установите ее, если ваше устройство испытывает затруднения с " +"воспроизведением на выходе (пропускает кадры)." + +msgid "Fast Decode" +msgstr "Быстрое кодирование" + +msgid "" +"Minimize latency between input to encoder and output of decoder.\n" +"\n" +" This is useful for broadcast of live streams.\n" +" Since HandBrake is not suitable for live stream broadcast " +"purposes, this setting is of little value here." +msgstr "" + +msgid "Zero Latency" +msgstr "Нулевая задержка" + +msgid "H.264 Profile:" +msgstr "Профиль x264:" + +msgid "" +"Limit the H.264 profile of the output stream.\n" +"\n" +" Overrides all other settings." +msgstr "" +"Профиль ограничения вывода потока H.264.\n" +"\n" +" Доминирует над всеми остальными настройками." + +msgid "H.264 Level:" +msgstr "Уровень x264:" + +msgid "" +"Sets and ensures compliance with the specified H.264 level.\n" +"\n" +" Overrides all other settings." +msgstr "" + +msgid "More Settings:" +msgstr "Дополнительно:" + +msgid "" +"Additional x264 settings.\n" +"\n" +" Colon separated list of x264 options." +msgstr "" +"Дополнительные настройки x264.\n" +"\n" +" Список вариантов опций разделять двоеточиями x264." + +msgid "Video" +msgstr "Видео" + +msgid "Add new audio settings to the list" +msgstr "Добавить новые аудио настройки в список" + +msgid "Remove the selected audio settings" +msgstr "Удалить выбранные настройки звука" + +msgid "Auto Passthru:" +msgstr "Авто-выбор декодера:" + +msgid "" +"Enable this if your playback device supports AAC. This permits AAC passthru " +"to be selected when automatic passthru selection is enabled." +msgstr "" + +msgid "" +"Enable this if your playback device supports AC-3. This permits AC-3 " +"passthru to be selected when automatic passthru selection is enabled." +msgstr "" + +msgid "" +"Enable this if your playback device supports DTS. This permits DTS passthru " +"to be selected when automatic passthru selection is enabled." +msgstr "" + +msgid "" +"Enable this if your playback device supports DTS-HD. This permits DTS-HD " +"passthru to be selected when automatic passthru selection is enabled." +msgstr "" + +msgid "Passthru Fallback:" +msgstr "Резервный декодер:" + +msgid "" +"Set the audio codec to encode with when a suitable track can not be found " +"for audio passthru." +msgstr "" +"Установить аудио кодек для кодирования с тем, что бы использовать когда " +"подходящий декодер не найден." + +msgid "Track Name:" +msgstr "Название дорожки:" + +msgid "" +"Set the audio track name. Players may use this in the audio selection list." +msgstr "" +"Установить название звуковой дорожки. Проигрыватели могут использовать это " +"списке выбора звука. " + +msgid "Sample Rate:" +msgstr "Частота дискретизации:" + +msgid "Set the sample rate of the output audio track." +msgstr "Установить частоту дискретизации дорожки вывода звука." + +msgid "Gain:" +msgstr "Усиление:" + +msgid "" +"<b>Audio Gain:</b> Adjust the amplification or attenuation of the output " +"audio track." +msgstr "" +"<b>Усиление звука:</b> Регулирует усиление или ослабление звуковой дорожки " +"вывода." + +msgid "" +"<b>Dynamic Range Compression:</b> Adjust the dynamic range of the output " +"audio track. \n" +"\n" +" For source audio that has a wide dynamic " +"range (very loud and very soft sequences), DRC allows you to 'compress' the " +"range by making loud sections softer and soft sections louder." +msgstr "" +"<b>Динамическое сжатие диапазона:</b> Устанавливает динамический диапазон " +"для звуковой дорожки вывода. \n" +"\n" +" Для источника звука, который имеет широкий " +"динамический диапазона (очень громкие и очень мягкие последовательности), " +"DRC позволяет «сжимать» диапазон, делая громкие разделы мягче и мягкие " +"разделы громче." + +msgid "" +"<b>Dynamic Range Compression:</b> Adjust the dynamic range of the output " +"audio track. \n" +"\n" +" For source audio that has a wide dynamic " +"range (very loud and very soft sequences), DRC allows you to 'compress' the " +"range by making loud sections softer and soft sections louder." +msgstr "" +"<b>Динамическое сжатие диапазона:</b> Устанавливает динамический диапазон " +"для звуковой дорожки вывода. \n" +"\n" +" Для источника звука, который имеет " +"широкий динамический диапазона (очень громкие и очень мягкие " +"последовательности), DRC позволяет «сжимать» диапазон, делая громкие разделы " +"мягче и мягкие разделы громче." + +msgid "Quality:" +msgstr "Качество:" + +msgid "" +"<b>Quality:</b> For output codec's that support it, adjust the quality of " +"the output.</b>" +msgstr "" +"<b>Качество:</b> Для выходного кодека, который поддерживают это, установить " +"качество вывода.</b>" + +msgid "Track" +msgstr "Дорожка" + +msgid "Encoder" +msgstr "Кодек" + +msgid "Bitrate" +msgstr "Битрэйт" + +msgid "Mix" +msgstr "Микшер" + +msgid "List of audio tracks available from your source." +msgstr "Список доступных в источнике звуковых дорожек." + +msgid "Set the audio codec to encode this track with." +msgstr "Установить аудио кодек для кодирования этой дорожки." + +msgid "Set the bitrate to encode this track with." +msgstr "Установить битрейт для кодирования этой дорожки." + +msgid "Set the mixdown of the output audio track." +msgstr "Установить микширование выходной звуковой дорожки." + +msgid "Audio" +msgstr "Аудио" + +msgid "Add new subtitle to the list" +msgstr "Добавить новый список субтитров" + +msgid "Add new SRT subtitle to the list" +msgstr "Добавить новый список субтитров SRT" + +msgid "Remove the selected subtitle settings" +msgstr "Удалить выбранные настройки субтитров" + +msgid "Language" +msgstr "Язык" + +msgid "Character Code" +msgstr "Кодировка" + +msgid "File" +msgstr "Файл" + +msgid "Offset (ms)" +msgstr "Смещение (мс)" + +msgid "List of subtitle tracks available from your source." +msgstr "Список дорожек субтитров доступных из источника." + +msgid "" +"Set the language of this subtitle. This value will be used by players in " +"subtitle menus." +msgstr "" +"Установить язык этих субтитров. Это значение будет использоваться " +"проигрывателями в меню субтитров." + +msgid "" +"Set the character code used by the SRT file you are importing. SRTs come in " +"all flavours of character sets. We translate the character set to UTF-8. " +"The source's character code is needed in order to perform this translation." +msgstr "" + +msgid "Srt File" +msgstr "Файл srt" + +msgid "Select the SRT file to import." +msgstr "Выберите файл srt для импорта." + +msgid "Adjust the offset in milliseconds between video and SRT timestamps" +msgstr "Установить смещение в миллисекундах между видео и метками времени SRT" + +msgid "Subtitles" +msgstr "Субтитры" + +msgid "<small>Reference Frames:</small>" +msgstr "<small>Ссылочные фреймы:</small>" + +msgid "" +"Sane values are ~1-6. The more you add, the better the compression, but the " +"slower the encode. Cel animation tends to benefit from more reference " +"frames a lot more than film content. Note that many hardware devices have " +"limitations on the number of supported reference frames, so if you're " +"encoding for a handheld or standalone player, don't touch this unless you're " +"absolutely sure you know what you're doing!" +msgstr "" + +msgid "<small>Maximum B-Frames:</small>" +msgstr "<small>Максимальные B-кадры:</small>" + +msgid "" +"Sane values are ~2-5. This specifies the maximum number of sequential B-" +"frames that the encoder can use. Large numbers generally won't help " +"significantly unless Adaptive B-frames is set to Optimal. Cel-animated " +"source material and B-pyramid also significantly increase the usefulness of " +"larger values. Baseline profile, as required for iPods and similar devices, " +"requires B-frames to be set to 0 (off)." +msgstr "" + +msgid "<small>Pyramidal B-Frames:</small>" +msgstr "<small>Пирамидальные B-кадры:</small>" + +msgid "" +"B-pyramid improves compression by creating a pyramidal structure (hence the " +"name) of B-frames, allowing B-frames to reference each other to improve " +"compression. Requires Max B-frames greater than 1; optimal adaptive B-" +"frames is strongly recommended for full compression benefit." +msgstr "" + +msgid "<small>Weighted P-Frames:</small>" +msgstr "<small>Взвешенные P-кадры:</small>" + +msgid "" +"Performs extra analysis to decide upon weighting parameters for each frame. " +"This improves overall compression slightly and improves the quality of fades " +"greatly. Baseline profile, as required for iPods and similar devices, " +"requires weighted P-frame prediction to be disabled. Note that some devices " +"and players, even those that support Main Profile, may have problems with " +"Weighted P-frame prediction: the Apple TV is completely incompatible with " +"it, for example." +msgstr "" + +msgid "" +"The 8x8 transform is the single most useful feature of x264 in terms of " +"compression-per-speed. It improves compression by at least 5% at a very " +"small speed cost and may provide an unusually high visual quality benefit " +"compared to its compression gain. However, it requires High Profile, which " +"many devices may not support." +msgstr "" + +msgid "8x8 Transform" +msgstr "Преобразование 8x8 " + +msgid "" +"After the encoder has done its work, it has a bunch of data that needs to be " +"compressed losslessly, similar to ZIP or RAR. H.264 provides two options " +"for this: CAVLC and CABAC. CABAC decodes a lot slower but compresses " +"significantly better (10-30%), especially at lower bitrates. If you're " +"looking to minimize CPU requirements for video playback, disable this " +"option. Baseline profile, as required for iPods and similar devices, " +"requires CABAC to be disabled." +msgstr "" + +msgid "CABAC Entropy Encoding" +msgstr "Энтропийное кодирование CABAC" + +msgid "<small><b>Encoding Features</b></small>" +msgstr "<small><b>Функции кодирования</b></small>" + +msgid "<small>Motion Est. Method:</small>" +msgstr "<small>Метод движения Est.:</small>" + +msgid "" +"Controls the motion estimation method. Motion estimation is how the encoder " +"estimates how each block of pixels in a frame has moved. A better motion " +"search method improves compression at the cost of speed.\n" +"\n" +" Diamond: performs an extremely fast and simple search using a " +"diamond pattern.\n" +"\n" +" Hexagon: performs a somewhat more effective but slightly slower " +"search using a hexagon pattern.\n" +"\n" +" Uneven Multi-Hex: performs a very wide search using a variety of " +"patterns, more accurately capturing complex motion.\n" +"\n" +" Exhaustive: performs a \"dumb\" search of every pixel in a wide " +"area. Significantly slower for only a small compression gain.\n" +"\n" +" Transformed Exhaustive: Like exhaustive, but makes even more " +"accurate decisions. Accordingly, somewhat slower, also for only a small " +"improvement." +msgstr "" + +msgid "<small>Subpel ME & Mode:</small>" +msgstr "" + +msgid "" +"This setting controls both subpixel-precision motion estimation and mode " +"decision methods.\n" +"\n" +" Subpixel motion estimation is used for refining motion estimates " +"beyond mere pixel accuracy, improving compression.\n" +"\n" +" Mode decision is the method used to choose how to encode each block " +"of the frame: a very important decision.\n" +"\n" +" SAD is the fastest method, followed by SATD, RD, RD refinement, and " +"the slowest, QPRD.\n" +"\n" +" 6 or higher is strongly recommended: Psy-RD, a very powerful psy " +"optimization that helps retain detail, requires RD.\n" +"\n" +" 11 disables all early terminations in analysis.\n" +"\n" +" 10 and 11, the most powerful and slowest options, require adaptive " +"quantization (aq-mode > 0) and trellis 2 (always)." +msgstr "" + +msgid "<small>Motion Est. Range:</small>" +msgstr "<small>Диапазон движения Est.:</small>" + +msgid "" +"This is the distance x264 searches from its best guess at the motion of a " +"block in order to try to find its actual motion. The default is fine for " +"most content, but extremely high motion video, especially at HD resolutions, " +"may benefit from higher ranges, albeit at a high speed cost." +msgstr "" + +msgid "<small>Adaptive Direct Mode:</small>" +msgstr "<small>Прямой адаптивный режим:</small>" + +msgid "" +"H.264 allows for two different prediction modes, spatial and temporal, in B-" +"frames.\n" +"\n" +" Spatial, the default, is almost always better, but temporal is " +"sometimes useful too.\n" +"\n" +" x264 can, at the cost of a small amount of speed (and accordingly " +"for a small compression gain), adaptively select which is better for each " +"particular frame." +msgstr "" + +msgid "<small>Adaptive B-Frames:</small>" +msgstr "<small>Адаптивные B-кадры:</small>" + +msgid "" +"x264 has a variety of algorithms to decide when to use B-frames and how many " +"to use.\n" +"\n" +" Fast mode takes roughly the same amount of time no matter how many B-" +"frames you specify. However, while fast, its decisions are often " +"suboptimal.\n" +"\n" +" Optimal mode gets slower as the maximum number of B-Frames " +"increases, but makes much more accurate decisions, especially when used with " +"B-pyramid." +msgstr "" + +msgid "<small>Partitions:</small>" +msgstr "<small>Разделы:</small>" + +msgid "" +"Mode decision picks from a variety of options to make its decision: this " +"option chooses what options those are. Fewer partitions to check means " +"faster encoding, at the cost of worse decisions, since the best option might " +"have been one that was turned off." +msgstr "" + +msgid "<small>Trellis:</small>" +msgstr "<small>Решетчатое кодирование:</small>" + +msgid "" +"Trellis fine-tunes the rounding of transform coefficients to squeeze out " +"3-5% more compression at the cost of some speed. \"Always\" uses trellis not " +"only during the main encoding process, but also during analysis, which " +"improves compression even more, albeit at great speed cost. Trellis costs " +"more speed at higher bitrates and requires CABAC." +msgstr "" + +msgid "<small><b>Analysis</b></small>" +msgstr "<small><b>Анализ</b></small>" + +msgid "<small>Adaptive Quantization Strength:</small>" +msgstr "<small>Адаптивная сила квантования:</small>" + +msgid "" +"Adaptive quantization controls how the encoder distributes bits across the " +"frame. Higher values take more bits away from edges and complex areas to " +"improve areas with finer detail." +msgstr "" + +msgid "<small>Psychovisual Rate Distortion:</small>" +msgstr "<small>Соотношение психовизуального искажения:</small>" + +msgid "" +"Psychovisual rate-distortion optimization takes advantage of the " +"characteristics of human vision to dramatically improve apparent detail and " +"sharpness. The effect can be made weaker or stronger by adjusting the " +"strength. Being an RD algorithm, it requires mode decision to be at least " +"\"6\"." +msgstr "" +"Психовизуальная оптимизация соотношению сигнал-шум использует преимущества " +"характеристик человеческого зрения, чтобы значительно улучшить детали и " +"резкость. Эффект можно ослабить или усилить, регулируя силу. Алгоритм RD " +"требует по меньшей мере установки режима \"6\"." + +msgid "<small>Psychovisual Trellis:</small>" +msgstr "<small>Психовизуальное решетчатое:</small>" + +msgid "" +"Psychovisual trellis is an experimental algorithm to further improve " +"sharpness and detail retention beyond what Psychovisual RD does. " +"Recommended values are around 0.2, though higher values may help for very " +"grainy video or lower bitrate encodes. Not recommended for cel animation " +"and other sharp-edged graphics." +msgstr "" + +msgid "Deblocking: " +msgstr "Деблокирование: " + +msgid "" +"H.264 has a built-in deblocking filter that smooths out blocking artifacts " +"after decoding each frame. This not only improves visual quality, but also " +"helps compression significantly. The deblocking filter takes a lot of CPU " +"power, so if you're looking to minimize CPU requirements for video playback, " +"disable it.\n" +"\n" +" The deblocking filter has two adjustable parameters, \"strength" +"\" (Alpha) and \"threshold\" (Beta). The former controls how strong (or " +"weak) the deblocker is, while the latter controls how many (or few) edges it " +"applies to. Lower values mean less deblocking, higher values mean more " +"deblocking. The default is 0 (normal strength) for both parameters." +msgstr "" + +msgid "" +"x264 normally zeroes out nearly-empty data blocks to save bits to be better " +"used for some other purpose in the video. However, this can sometimes have " +"slight negative effects on retention of subtle grain and dither. Don't " +"touch this unless you're having banding issues or other such cases where you " +"are having trouble keeping fine noise." +msgstr "" +"x264 обычно обнуляет почти пустые блоки данных для сохранения битов, которые " +"будут лучше использовать для других целей в видео. Тем не менее, иногда это " +"может иметь небольшое отрицательное воздействие на сохранение тонких мелких " +"частиц и размытие. Не касайтесь этого, если не имеете проблем хранения " +"мелких шумов." + +msgid "No DCT Decimate" +msgstr "Не опустошать DCT" + +msgid "<small><b>Psychovisual</b></small>" +msgstr "<small><b>Психовизуальное</b></small>" + +msgid "" +"Your selected options will appear here. \n" +" You can edit these and add additional options. \n" +"\n" +" Default values will not be shown. The defaults are:\n" +" ref=3:bframes=3:b-adapt=fast:direct=spatial:\n" +" b-pyramid=normal:weightp=2:me=hex:merange=16:\n" +" subme=7:partitions=p8x8,b8x8,i8x8,i4x4:8x8dct=1:\n" +" deblock=0,0:trellis=1:psy-rd=1,0:aq-strength=1.0:\n" +" no-fast-pskip=0:no-dct-decimate=0:cabac=1" +msgstr "" + +msgid "<small><b>Current x264 Advanced Option String</b></small>" +msgstr "<small><b>Дополнительная строка текущей опции x264</b></small>" + +msgid "" +"Your selected options will appear here. \n" +" You can edit these and add additional options." +msgstr "" + +msgid "<small><b>Current FFMpeg Advanced Option String</b></small>" +msgstr "<small><b>Дополнительная строка текущей опции FFMpeg</b></small>" + +msgid "Advanced" +msgstr "Дополнительно" + +msgid "Add chapter markers to output file." +msgstr "Добавить маркеры глав в выходной файл." + +msgid "Chapter Markers" +msgstr "Маркеры глав" + +msgid "Chapters" +msgstr "Главы" + +msgid "Title:" +msgstr "Название:" + +msgid "Actors:" +msgstr "Актеры:" + +msgid "Director:" +msgstr "Режиссёр:" + +msgid "Release Date:" +msgstr "Дата выпуска:" + +msgid "Comment:" +msgstr "Комментарий:" + +msgid "Genre:" +msgstr "Жанр:" + +msgid "Description:" +msgstr "Описание:" + +msgid "Plot:" +msgstr "Сюжет:" + +msgid "Tags" +msgstr "Теги" + +msgid "_Save" +msgstr "_Сохранить" + +msgid "Save current settings to new preset." +msgstr "Сохранить текущие настройки в новую предустановку." + +msgid "Delete the currently selected preset." +msgstr "Удалить сейчас выбранную предустановку." + +msgid "_Options" +msgstr "_Параметры" + +msgid "Preset Options" +msgstr "Параметры предустановок" + +msgid "<b>Presets</b>" +msgstr "<b>Предустановки</b>" + +msgid "Preferences" +msgstr "Параметры" + +msgid "Automatically check for updates" +msgstr "Автоматически проверять наличие обновлений" + +msgid "When all encodes are complete" +msgstr "Когда все кодирование завершено" + +msgid "Use automatic naming (uses modified source name)" +msgstr "" +"Использовать автоматический идентификатор (использует измененное исходное " +"имя)" + +msgid "Add chapters to destination name" +msgstr "Добавить главы в имя назначения" + +msgid "Add title # to destination name" +msgstr "Добавить название # в имя назначения" + +msgid "Use iPod/iTunes friendly (.m4v) file extension for MP4" +msgstr "Использовать дружественное iPod/iTunes расширение файла (.m4v) для MP4" + +msgid "Number of previews" +msgstr "Число миниатюр" + +msgid "Filter short titles (seconds)" +msgstr "Фильтр коротких наименований (в секундах)" + +msgid "Show system tray icon" +msgstr "Показывать значек в системном лотке" + +msgid "General" +msgstr "Общие" + +msgid "Preferred Language:" +msgstr "Предпочитаемый язык:" + +msgid "DUB Foreign language audio" +msgstr "Дублированный иностранный язык аудио" + +msgid "Use foreign language audio and add subtitles" +msgstr "Использовать иностранный язык аудио и добавлять субтитры" + +msgid "Add Closed Captions when available" +msgstr "Добавлять субтитры для глухих когда возможно" + +msgid "Audio/Subtitles" +msgstr "Аудио/субтитры" + +msgid "Constant Quality fractional granularity" +msgstr "Постоянное качество детализации" + +msgid "Use dvdnav (instead of libdvdread)" +msgstr "Использовать dvdnav (вместо libdvdread)" + +msgid "Put individual encode logs in same location as movie" +msgstr "" +"Класть индивидуальные логи кодирования в то же расположение что и фильм" + +msgid "Activity Log Verbosity Level" +msgstr "Подробный журнал уровня деятельности" + +msgid "Activity Log Longevity" +msgstr "Долговечный журнала операций" + +msgid "Scale down High Definition previews" +msgstr "Уменьшать высокий размер просмотра" + +msgid "Automatically Scan DVD when loaded" +msgstr "Автоматически сканировать DVD при загрузке" + +msgid "Scans the DVD whenever a new disc is loaded" +msgstr "Сканировать DVD после загрузки нового диска" + +msgid "Enable Advanced Auto-Passthru options" +msgstr "Включить дополнительные опции авто-выбора декодера" + +msgid "" +"Enabling this adds extra widgets to the audio panel that allow\n" +" you to specify which particular codecs shall be passed\n" +" and which codec to use when passthru is not possible" +msgstr "" + +msgid "Hide Advanced Video Options Tab" +msgstr "Скрыть вкладку дополнительной настройки видео" + +msgid "" +"Use advanced video options at your own risk.\n" +"We recommend that you use the controls available\n" +"on the Video tab instead." +msgstr "" + +msgid "Allow Tweaks" +msgstr "Разрешить тонкие настройки" + +msgid "Allow HandBrake For Dummies" +msgstr "" + +msgid "Setting:" +msgstr "Настройка:" + +msgid "Folder Name:" +msgstr "Имя папки::" + +msgid "Preset Name:" +msgstr "Название предустановки:" + +msgid "<b>Custom Picture Dimensions</b>" +msgstr "<b>Пользовательский размер изображения</b>" + +msgid "Maximum Width:" +msgstr "Максимальная ширина:" + +msgid "Enable maximum width limit." +msgstr "Включить лимит максимальной ширины." + +msgid "" +"This is the maximum width that the video will be stored at. Whenever a new " +"source is loaded, this value will be applied if the source width is greater. " +"Setting this to 0 means there is no maximum width." +msgstr "" + +msgid "Maximum Height:" +msgstr "Максимальная высота:" + +msgid "Enable maximum height limit." +msgstr "Включить лимит максимальной высоты." + +msgid "" +"This is the maximum height that the video will be stored at. Whenever a new " +"source is loaded, this value will be applied if the source height is " +"greater. Setting this to 0 means there is no maximum height." +msgstr "" + +msgid "<b>Description</b>" +msgstr "<b>Описание</b>" + +msgid "HandBrake Queue" +msgstr "Очередь" + +msgid "Start" +msgstr "Старт" + +msgid "Pause" +msgstr "Пауза" + +msgid "Edit" +msgstr "Изменить" + +msgid "_Start" +msgstr "_Старт" + +msgid "_Pause" +msgstr "_Пауза" + +msgid "_Edit" +msgstr "_Изменить" + +msgid "Open Preview Window" +msgstr "Открыть окно предварительного просмотра" + +msgid "Show Preview" +msgstr "Предварительный просмотр" + +msgid "Left Crop" +msgstr "Обрезка слева" + +msgid "Top Crop" +msgstr "Обрезка сверху" + +msgid "Bottom Crop" +msgstr "Обрезка снизу" + +msgid "Right Crop" +msgstr "Обрезка справа" + +msgid "Auto Crop" +msgstr "Автокадрирование" + +msgid "Automatically crop black borders around edges of the video." +msgstr "Автоматически обрезать черные полосы по краям видео." + +msgid "Loose Crop" +msgstr "Произвольное кадрирование" + +msgid "Loose" +msgstr "Произвольно" + +msgid "Crop Dimensions:" +msgstr "Размер:" + +msgid "<b>Cropping</b>" +msgstr "<b>Кадрирование</b>" + +msgid "width:" +msgstr "Ширина:" + +msgid "" +"This is the width that the video will be stored at. The actual display " +"dimensions will differ if the pixel aspect ratio is not 1:1." +msgstr "" + +msgid "height:" +msgstr "Высота:" + +msgid "" +"This is the height that the video will be stored at. The actual display " +"dimensions will differ if the pixel aspect ratio is not 1:1." +msgstr "" + +msgid "Optimal for source" +msgstr "Оптимально для источника" + +msgid "" +"If enabled, select the 'optimal' storage resolution. This will be the " +"resolution that most closely matches the source resolution after cropping." +msgstr "" + +msgid "" +"<b>Anamorphic Modes:</b>\n" +"<small><tt>\n" +"None - Force pixel aspect ratio to 1:1.\n" +"Loose - Align dimensions to chosen 'Alignment' value \n" +" and pick pixel aspect ratio that preserves the\n" +" original display aspect ratio\n" +"Strict - Keep original source dimensions and pixel \n" +" aspect ratio</tt></small>" +msgstr "" + +msgid "Alignment:" +msgstr "Выравнивание:" + +msgid "" +"Align storage dimensions to multiples of this value.\n" +"\n" +"Encoders are most effecient when the video dimensions are aligned to some " +"specific value (usually 16). Setting this to some other value will result in " +"slightly larger file size." +msgstr "" + +msgid "<b>Storage</b>" +msgstr "<b>Разрешение</b>" + +msgid "" +"This is the display width. It is the result of scaling the storage " +"dimensions by the pixel aspect." +msgstr "" + +msgid "Pixel Aspect:" +msgstr "Соотношение пикселей:" + +msgid "" +"Pixel aspect defines the shape of the pixels. A 1:1 ratio defines a square " +"pixel. Other values define rectangular shapes. Players will scale the image " +"in order to achieve the specified aspect." +msgstr "" + +msgid "" +"If enabled, the original display aspect of the source will be maintained." +msgstr "" +"Если включено, оригинальный формата соотношения источника будет сохранен." + +msgid "Display Aspect:" +msgstr "Соотношение:" + +msgid "<b>Display</b>" +msgstr "<b> Отображение</b>" + +msgid "Dimensions" +msgstr "Размер" + +msgid "Grayscale" +msgstr "Градации серого" + +msgid "If enabled, filter colour components out of video." +msgstr "Если включено, фильтр выходных компонентов цвета из видео." + +msgid "Deblock:" +msgstr "Разделять блоки:" + +msgid "" +"The deblocking filter removes a common type of compression artifact. If your " +"source exhibits 'blockiness', this filter may help clean it up." +msgstr "" + +msgid "Denoise:" +msgstr "Шумоподавление:" + +msgid "" +"The denoise filter is a low pass filter that removes noise. Film grain and " +"other types of high frequency noise are difficult to compress. Using this " +"filter on such sources can result in smaller file sizes." +msgstr "" + +msgid "" +"Custom denoise filter string format\n" +" SpatialLuma:SpatialChroma:TemporalLuma:TemporalChroma" +msgstr "" +"Пользовательский фильтр удаления шумов формата\n" +" SpatialLuma:SpatialChroma:TemporalLuma:TemporalChroma" + +msgid "Detelecine:" +msgstr "Обратная телекинопроекция:" + +msgid "" +"This filter removes 'combing' artifacts that are the result of telecining. " +"Telecining is a process that adjusts film framerates that are 24fps to NTSC " +"video frame rates which are 30fps." +msgstr "" + +msgid "" +"Custom detelecine filter string format\n" +" JunkLeft:JunkRight:JunkTop:JunkBottom:StrictBreaks:MetricPlane:Parity" +msgstr "" + +msgid "Decomb" +msgstr "Убрать гребенку" + +msgid "" +"Choose decomb or deinterlace filter options.\n" +"\n" +"The decomb filter selectively deinterlaces frames that appear to be " +"interlaced. This will preserve quality in frames that are not interlaced.\n" +"\n" +"The classic deinterlace filter is applied to all frames. Frames that are not " +"interlaced will suffer some quality degradation." +msgstr "" + +msgid "Deinterlace" +msgstr "Деинтерлейсинг" + +msgid "Decomb:" +msgstr "Убрать гребенку:" + +msgid "" +"The decomb filter selectively deinterlaces frames that appear to be " +"interlaced. This will preserve quality in frames that are not interlaced." +msgstr "" + +msgid "" +"Custom decomb filter string format\n" +" Mode:SpatialMetric:MotionThresh:SpatialThresh:BlockThresh:BlockWidth:" +"BlockHeight:MagnitudeThres:VarianceThres:LaplacianThresh:DilationThresh:" +"ErosionThresh:NoiseThresh:MaxSearchDistance:PostProcessing:Parity" +msgstr "" + +msgid "Deinterlace:" +msgstr "Деинтерлейсинг:" + +msgid "" +"The classic deinterlace filter is applied to all frames. Frames that are not " +"interlaced will suffer some quality degradation." +msgstr "" + +msgid "" +"Custom deinterlace filter string format\n" +" YadifMode:YadifParity:McdintMode:McdeintQp" +msgstr "" + +msgid "Filters" +msgstr "Фильтры" + +msgid "Select preview frames." +msgstr "Выбор кадра для миниатюры." + +msgid "" +"Encode and play a short sequence of video starting from the current preview " +"position." +msgstr "" +"Кодировать и воспроизводить короткие последовательности видео, начиная с " +"текущего положения просмотра." + +msgid "<b>Duration:</b>" +msgstr "<b>Продолжительность:</b>" + +msgid "Set the duration of the live preview in seconds." +msgstr "Установить продолжительность предварительного просмотра в секундах." + +msgid "Show Cropped area of the preview" +msgstr "Показать просмотр обрезанных областей" + +msgid "Show Crop" +msgstr "Показать кадрирование" + +msgid "View Fullscreen Preview" +msgstr "Вид просмотра в полный экран" + +msgid "Fullscreen" +msgstr "Полный экран" + +msgid "Hide the picture settings window while leaving the preview visible." +msgstr "" +"Скрыть окно настройки изображения, оставляя видным предварительный просмотр." + +msgid "Hide Settings" +msgstr "Скрыть настройки" + +msgid "Preview" +msgstr "Предварительный просмотр" + +msgid "About HandBrake" +msgstr "О программе" + +msgid "<b>A new version of HandBrake is available!</b>" +msgstr "<b>Доступна новая версия HandBrake!</b>" + +msgid "HandBrake xxx is now available (you have yyy)." +msgstr "Доступна новая версия HandBrake xxx (у вас версия yyy)." + +msgid "Release Notes" +msgstr "Заметка о релизе" + +msgid "Skip This Version" +msgstr "Пропустить эту версию" + +msgid "Remind Me Later" +msgstr "Напомнить позже" + +msgid "Title Number:" +msgstr "Номер названия:" + +msgid "Detected DVD devices:" +msgstr "Обнаружено устройство DVD:" + +msgid "Same As Source:" +msgstr "Так же, как в источнике:" + +msgid "Same As Source" +msgstr "Так же, как в источнике" + +msgid "<small>Same as source</small>" +msgstr "<small>Так же, как в источнике</small>" + +msgid "Same as source" +msgstr "Так же, как в источнике" + +msgid "Same as source " +msgstr "Так же, как в источнике " + +msgid "Source" +msgstr "Источник" + +msgid "Codec" +msgstr "Кодек" + +msgid "Gain" +msgstr "Усиление" + +msgid "Sample Rate" +msgstr "Частота дискретизации" + +msgid "Import SRT" +msgstr "Импорт SRT" + +msgid "Subtitle" +msgstr "Субтитры" + +msgid "Index" +msgstr "Индекс" + +msgid "Duration" +msgstr "Продолжительность" + +msgid "Title" +msgstr "Название" + +msgid "Stop Scan" +msgstr "Остановить сканирование" + +msgid "Encode Complete" +msgstr "Кодирование завершено" + +msgid "" +"Encode Complete\n" +"Put down that cocktail, Your HandBrake queue is done!" +msgstr "" +"Кодирование завершено\n" +"HandBrake завершил кодировать этот коктейль!" + +msgid "Put down that cocktail, Your HandBrake queue is done!" +msgstr "HandBrake завершил кодировать этот коктейль!" + +msgid "HandBrake's normal, default settings." +msgstr "Предустановка нормального качества, настройки по умолчанию." + +msgid "" +"HandBrake's settings for compatibility with all Apple devices (including the " +"iPod 6G and later). Includes Dolby Digital audio for surround sound." +msgstr "" +"Настройки для совместимости со всеми устройствами Apple, (в том числе iPod " +"6G и более поздних). Включает в себя аудио Dolby Digital для объемного звука." + +msgid "Universal" +msgstr "Универсальный" + +msgid "" +"HandBrake's settings for playback on the iPod with Video (all generations)." +msgstr "Настройки для воспроизведения на iPod с видео (всех поколений)." + +msgid "iPod" +msgstr "" + +msgid "" +"HandBrake's settings for handheld iOS devices (iPhone 4, iPod touch 3G and " +"later)." +msgstr "" +"Настройки для карманных устройств IOS (iPhone 4, IPod Touch 3G и выше)." + +msgid "iPhone & iPod touch" +msgstr "" + +msgid "HandBrake's settings for playback on the iPad (all generations)." +msgstr "Настройки для воспроизведения на IPad (всех поколений)." + +msgid "iPad" +msgstr "" + +msgid "" +"HandBrake's settings for the original AppleTV. Includes Dolby Digital audio " +"for surround sound. Also compatible with iOS devices released since 2009." +msgstr "" +"Настройки для оригинального AppleTV. Включают в себя аудио Dolby Digital для " +"объемного звука. Также совместим с устройствами IOS, выпущенных после 2009 " +"года." + +msgid "AppleTV" +msgstr "" + +msgid "" +"HandBrake's settings for the second-generation AppleTV. Includes Dolby " +"Digital audio for surround sound. NOT compatible with the original AppleTV." +msgstr "" +"Настройки для второго поколения AppleTV. Включают в себя аудио Dolby Digital " +"для объемного звука. Не совместим с оригинальным AppleTV." + +msgid "AppleTV 2" +msgstr "" + +msgid "" +"HandBrake's settings for the third-generation AppleTV. Includes Dolby " +"Digital audio for surround sound. NOT compatible with the original AppleTV. " +"May stutter on the second-generation AppleTV." +msgstr "" +"Настройки для третьего поколения AppleTV. Включают в себя аудио Dolby " +"Digital для объемного звука. Не совместим с оригинальным AppleTV. Может " +"заикаться на второом поколении AppleTV." + +msgid "AppleTV 3" +msgstr "" + +msgid "HandBrake's settings for midrange devices running Android 2.3 or later." +msgstr "" +"Настройки для устройств среднего класса под управлением Android 2.3 или " +"более поздних." + +msgid "Android" +msgstr "Андроид" + +msgid "HandBrake's preset for tablets running Android 2.3 or later." +msgstr "Предустановка для планшета Android 2.3 или более поздних." + +msgid "Android Tablet" +msgstr "Планшет андроид" + +msgid "Normal" +msgstr "Стандартный" + +msgid "HandBrake's general-purpose preset for High Profile H.264 video." +msgstr "Предустановка общего назначения для видео высокого качества H.264." + +msgid "High Profile" +msgstr "Высокое качество" + +msgid "Regular" +msgstr "Обычные" + +msgid "Devices" +msgstr "Устройства" + +msgid "Keep Aspect" +msgstr "Сохранять соотношение" + +msgid "Encoding: %s%s%.2f %%" +msgstr "Кодирование: %s%s%.2f %%" + +msgid "Chapter" +msgstr "Глава" + +msgid "Chapter %2d" +msgstr "Глава %2d" diff --git a/gtk/src/audiohandler.c b/gtk/src/audiohandler.c index 72f58bfa7..cdf1d16e3 100644 --- a/gtk/src/audiohandler.c +++ b/gtk/src/audiohandler.c @@ -11,6 +11,7 @@ * any later version. */ +#include <glib/gi18n.h> #include "ghbcompat.h" #include "hb.h" #include "settings.h" @@ -71,7 +72,7 @@ ghb_select_audio_codec(gint mux, hb_audio_config_t *aconfig, gint acodec, gint f if (enc->codec == fallback && !(enc->muxers & mux)) { - if ( mux == HB_MUX_MKV ) + if ( mux & HB_MUX_MASK_MKV ) fallback = HB_ACODEC_LAME; else fallback = HB_ACODEC_FAAC; @@ -553,7 +554,7 @@ ghb_audio_list_refresh_selected(signal_user_data_t *ud) drc = ghb_settings_get_double(asettings, "AudioTrackDRCSlider"); if (drc < 1.0) - s_drc = g_strdup("Off"); + s_drc = g_strdup(_("Off")); else s_drc = g_strdup_printf("%.1f", drc); @@ -620,7 +621,7 @@ ghb_audio_list_refresh(signal_user_data_t *ud) drc = ghb_settings_get_double(asettings, "AudioTrackDRCSlider"); if (drc < 1.0) - s_drc = g_strdup("Off"); + s_drc = g_strdup(_("Off")); else s_drc = g_strdup_printf("%.1f", drc); @@ -642,6 +643,27 @@ ghb_audio_list_refresh(signal_user_data_t *ud) } } +static void enable_quality_widget(signal_user_data_t *ud, int acodec) +{ + GtkWidget *widget1, *widget2, *widget3; + + widget1 = GHB_WIDGET(ud->builder, "AudioTrackQualityEnable"); + widget2 = GHB_WIDGET(ud->builder, "AudioTrackQualityValue"); + widget3 = GHB_WIDGET(ud->builder, "AudioTrackQuality"); + if (hb_audio_quality_get_default(acodec) == HB_INVALID_AUDIO_QUALITY) + { + gtk_widget_hide(widget1); + gtk_widget_hide(widget2); + gtk_widget_hide(widget3); + } + else + { + gtk_widget_show(widget1); + gtk_widget_show(widget2); + gtk_widget_show(widget3); + } +} + G_MODULE_EXPORT void audio_codec_changed_cb(GtkWidget *widget, signal_user_data_t *ud) { @@ -654,6 +676,7 @@ audio_codec_changed_cb(GtkWidget *widget, signal_user_data_t *ud) acodec_code = ghb_lookup_combo_int("AudioEncoder", gval); ghb_value_free(gval); + enable_quality_widget(ud, acodec_code); if (block_updates) { prev_acodec = acodec_code; @@ -829,7 +852,7 @@ G_MODULE_EXPORT gchar* format_drc_cb(GtkScale *scale, gdouble val, signal_user_data_t *ud) { if (val < 1.0) - return g_strdup_printf("%-7s", "Off"); + return g_strdup_printf("%-7s", _("Off")); else return g_strdup_printf("%-7.1f", val); } @@ -903,7 +926,7 @@ drc_widget_changed_cb(GtkWidget *widget, gdouble drc, signal_user_data_t *ud) char *s_drc; if (drc < 0.99) - s_drc = g_strdup("Off"); + s_drc = g_strdup(_("Off")); else s_drc = g_strdup_printf("%.1f", drc); ghb_ui_update( ud, "AudioTrackDRCValue", ghb_string_value(s_drc)); @@ -1018,7 +1041,7 @@ ghb_add_audio_to_ui(GtkBuilder *builder, const GValue *settings) drc = ghb_settings_get_double(settings, "AudioTrackDRCSlider"); if (drc < 1.0) - s_drc = g_strdup("Off"); + s_drc = g_strdup(_("Off")); else s_drc = g_strdup_printf("%.1f", drc); diff --git a/gtk/src/callbacks.c b/gtk/src/callbacks.c index eead66275..a6839c42b 100644 --- a/gtk/src/callbacks.c +++ b/gtk/src/callbacks.c @@ -21,6 +21,7 @@ #include <time.h> #include <glib/gstdio.h> +#include <glib/gi18n.h> #include <gio/gio.h> #include "ghbcompat.h" @@ -324,7 +325,7 @@ on_quit1_activate(GtkMenuItem *quit, signal_user_data_t *ud) g_debug("on_quit1_activate ()"); if (state & (GHB_STATE_WORKING|GHB_STATE_SEARCHING)) { - if (ghb_cancel_encode2(ud, "Closing HandBrake will terminate encoding.\n")) + if (ghb_cancel_encode2(ud, _("Closing HandBrake will terminate encoding.\n"))) { ghb_hb_cleanup(FALSE); prune_logs(ud); @@ -563,21 +564,17 @@ static const gchar* get_extension(GValue *settings) { int container; - const gchar *extension = "error"; + const gchar *extension; container = ghb_settings_combo_int(settings, "FileFormat"); - if (container == HB_MUX_MP4) - { - extension = "mp4"; - if (ghb_settings_get_boolean(settings, "UseM4v")) - { - extension = "m4v"; - } - } - else if (container == HB_MUX_MKV) + if ((container & HB_MUX_MASK_MP4) && + ghb_settings_get_boolean(settings, "UseM4v")) { - extension = "mkv"; + return "m4v"; } + extension = hb_container_get_default_extension(container); + if (extension == NULL) + extension = "error"; return extension; } @@ -776,7 +773,7 @@ update_source_label(signal_user_data_t *ud, const gchar *source, gboolean update } else { - label = "No Title Found"; + label = _("No Title Found"); gtk_label_set_text (GTK_LABEL(widget), label); ghb_settings_set_string(ud->settings, "volume_label", label); return FALSE; @@ -860,7 +857,7 @@ source_dialog_extra_widgets( gtk_combo_box_get_model(GTK_COMBO_BOX(combo)))); link = drives = dvd_device_list(); - gtk_combo_box_text_append_text (combo, "Not Selected"); + gtk_combo_box_text_append_text (combo, _("Not Selected")); while (link != NULL) { gchar *name = get_dvd_device_name(link->data); @@ -887,7 +884,7 @@ show_scan_progress(signal_user_data_t *ud) gtk_widget_show(GTK_WIDGET(progress)); label = GTK_LABEL(GHB_WIDGET(ud->builder, "source_title")); - gtk_label_set_text( label, "Scanning ..." ); + gtk_label_set_text( label, _("Scanning ...") ); } static void @@ -907,8 +904,8 @@ start_scan( widget = GHB_WIDGET(ud->builder, "sourcetoolbutton"); gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(widget), "hb-stop"); - gtk_tool_button_set_label(GTK_TOOL_BUTTON(widget), "Stop Scan"); - gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(widget), "Stop Scan"); + gtk_tool_button_set_label(GTK_TOOL_BUTTON(widget), _("Stop Scan")); + gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(widget), _("Stop Scan")); //gtk_widget_set_sensitive(widget, FALSE); action = GHB_ACTION(ud->builder, "source_action"); @@ -1082,7 +1079,7 @@ dvd_source_activate_cb(GtkAction *action, signal_user_data_t *ud) void ghb_update_destination_extension(signal_user_data_t *ud) { - static gchar *containers[] = {".mkv", ".mp4", ".m4v", NULL}; + static gchar *containers[] = {".mkv", ".mp4", ".m4v", ".error", NULL}; gchar *filename; const gchar *extension; gint ii; @@ -1262,7 +1259,7 @@ window_delete_event_cb(GtkWidget *widget, GdkEvent *event, signal_user_data_t *u g_debug("window_delete_event_cb ()"); if (state & (GHB_STATE_WORKING|GHB_STATE_SEARCHING)) { - if (ghb_cancel_encode2(ud, "Closing HandBrake will terminate encoding.\n")) + if (ghb_cancel_encode2(ud, _("Closing HandBrake will terminate encoding.\n"))) { ghb_hb_cleanup(FALSE); prune_logs(ud); @@ -1284,12 +1281,41 @@ update_acodec_combo(signal_user_data_t *ud) ghb_grey_combo_options (ud); } +static void +set_visible(GtkWidget *widget, gboolean visible) +{ + if (visible) + { + gtk_widget_show_now(widget); + } + else + { + gtk_widget_hide(widget); + } +} + +static void show_container_options(signal_user_data_t *ud) +{ + GtkWidget *w1, *w2, *w3; + w1 = GHB_WIDGET(ud->builder, "Mp4LargeFile"); + w2 = GHB_WIDGET(ud->builder, "Mp4HttpOptimize"); + w3 = GHB_WIDGET(ud->builder, "Mp4iPodCompatible"); + + gint mux = ghb_settings_combo_int(ud->settings, "FileFormat"); + gint enc = ghb_settings_combo_int(ud->settings, "VideoEncoder"); + + set_visible(w1, (mux == HB_MUX_MP4V2)); + set_visible(w2, (mux & HB_MUX_MASK_MP4)); + set_visible(w3, (mux & HB_MUX_MASK_MP4) && (enc == HB_VCODEC_X264)); +} + G_MODULE_EXPORT void container_changed_cb(GtkWidget *widget, signal_user_data_t *ud) { g_debug("container_changed_cb ()"); ghb_widget_to_setting(ud->settings, widget); ghb_check_dependency(ud, widget, NULL); + show_container_options(ud); update_acodec_combo(ud); ghb_update_destination_extension(ud); ghb_clear_presets_selection(ud); @@ -1398,7 +1424,7 @@ show_title_info(signal_user_data_t *ud, hb_title_t *title) } else { - gchar *label = "No Title Found"; + gchar *label = _("No Title Found"); gtk_label_set_text (GTK_LABEL(widget), label); ghb_settings_set_string(ud->settings, "volume_label", label); } @@ -1579,7 +1605,7 @@ set_title_settings(GValue *settings, gint titleindex) } else { - gchar *label = "No Title Found"; + gchar *label = _("No Title Found"); ghb_settings_set_string(settings, "volume_label", label); } } @@ -1883,6 +1909,7 @@ vcodec_changed_cb(GtkWidget *widget, signal_user_data_t *ud) ghb_widget_to_setting(ud->settings, widget); ghb_check_dependency(ud, widget, NULL); + show_container_options(ud); ghb_clear_presets_selection(ud); ghb_live_reset(ud); ghb_vquality_range(ud, &vqmin, &vqmax, &step, &page, &digits, &inverted); @@ -2134,28 +2161,28 @@ scale_changed_cb(GtkWidget *widget, signal_user_data_t *ud) gchar *text; - text = ghb_settings_get_boolean(ud->settings, "PictureAutoCrop") ? "On" : "Off"; + text = ghb_settings_get_boolean(ud->settings, "PictureAutoCrop") ? _("On") : _("Off"); widget = GHB_WIDGET (ud->builder, "crop_auto"); gtk_label_set_text (GTK_LABEL(widget), text); - text = ghb_settings_get_boolean(ud->settings, "autoscale") ? "On" : "Off"; + text = ghb_settings_get_boolean(ud->settings, "autoscale") ? _("On") : _("Off"); widget = GHB_WIDGET (ud->builder, "scale_auto"); gtk_label_set_text (GTK_LABEL(widget), text); switch (ghb_settings_combo_int(ud->settings, "PicturePAR")) { case 0: - text = "Off"; + text = _("Off"); break; case 1: - text = "Strict"; + text = _("Strict"); break; case 2: - text = "Loose"; + text = _("Loose"); break; case 3: - text = "Custom"; + text = _("Custom"); break; default: - text = "Unknown"; + text = _("Unknown"); break; } widget = GHB_WIDGET (ud->builder, "scale_anamorphic"); @@ -2226,7 +2253,7 @@ quit_cb(countdown_t *cd) gtk_main_quit(); return FALSE; } - str = g_strdup_printf("%s\n\n%s in %d seconds ...", + str = g_strdup_printf(_("%s\n\n%s in %d seconds ..."), cd->msg, cd->action, cd->timeout); gtk_message_dialog_set_markup(cd->dlg, str); g_free(str); @@ -2248,7 +2275,7 @@ shutdown_cb(countdown_t *cd) gtk_main_quit(); return FALSE; } - str = g_strdup_printf("%s\n\n%s in %d seconds ...", + str = g_strdup_printf(_("%s\n\n%s in %d seconds ..."), cd->msg, cd->action, cd->timeout); gtk_message_dialog_set_markup(cd->dlg, str); g_free(str); @@ -2267,7 +2294,7 @@ suspend_cb(countdown_t *cd) ghb_suspend_gpm(); return FALSE; } - str = g_strdup_printf("%s\n\n%s in %d seconds ...", + str = g_strdup_printf(_("%s\n\n%s in %d seconds ..."), cd->msg, cd->action, cd->timeout); gtk_message_dialog_set_markup(cd->dlg, str); g_free(str); @@ -2297,7 +2324,7 @@ ghb_countdown_dialog( // Toss up a warning dialog dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, type, GTK_BUTTONS_NONE, - "%s\n\n%s in %d seconds ...", + _("%s\n\n%s in %d seconds ..."), message, action, timeout); gtk_dialog_add_buttons( GTK_DIALOG(dialog), cancel, GTK_RESPONSE_CANCEL, @@ -2366,13 +2393,13 @@ ghb_cancel_encode(signal_user_data_t *ud, const gchar *extra_msg) // Toss up a warning dialog dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE, - "%sYour movie will be lost if you don't continue encoding.", + _("%sYour movie will be lost if you don't continue encoding."), extra_msg); gtk_dialog_add_buttons( GTK_DIALOG(dialog), - "Cancel Current and Stop", 1, - "Cancel Current, Start Next", 2, - "Finish Current, then Stop", 3, - "Continue Encoding", 4, + _("Cancel Current and Stop"), 1, + _("Cancel Current, Start Next"), 2, + _("Finish Current, then Stop"), 3, + _("Continue Encoding"), 4, NULL); response = gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy (dialog); @@ -2406,11 +2433,11 @@ ghb_cancel_encode2(signal_user_data_t *ud, const gchar *extra_msg) // Toss up a warning dialog dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE, - "%sYour movie will be lost if you don't continue encoding.", + _("%sYour movie will be lost if you don't continue encoding."), extra_msg); gtk_dialog_add_buttons( GTK_DIALOG(dialog), - "Cancel Current and Stop", 1, - "Continue Encoding", 4, + _("Cancel Current and Stop"), 1, + _("Continue Encoding"), 4, NULL); response = gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy (dialog); @@ -2709,7 +2736,7 @@ working_status_string(signal_user_data_t *ud, ghb_instance_status_t *status) } if (qcount > 1) { - job_str = g_strdup_printf("job %d of %d, ", index+1, qcount); + job_str = g_strdup_printf(_("job %d of %d, "), index+1, qcount); } else { @@ -2719,12 +2746,12 @@ working_status_string(signal_user_data_t *ud, ghb_instance_status_t *status) { if (status->job_cur == 1 && subtitle_scan) { - task_str = g_strdup_printf("pass %d (subtitle scan) of %d, ", + task_str = g_strdup_printf(_("pass %d (subtitle scan) of %d, "), status->job_cur, status->job_count); } else { - task_str = g_strdup_printf("pass %d of %d, ", + task_str = g_strdup_printf(_("pass %d of %d, "), status->job_cur, status->job_count); } } @@ -2737,8 +2764,8 @@ working_status_string(signal_user_data_t *ud, ghb_instance_status_t *status) if (status->rate_cur > 0.0) { status_str= g_strdup_printf( - "Encoding: %s%s%.2f %%" - " (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)", + _("Encoding: %s%s%.2f %%" + " (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)"), job_str, task_str, 100.0 * status->progress, status->rate_cur, status->rate_avg, status->hours, @@ -2747,8 +2774,8 @@ working_status_string(signal_user_data_t *ud, ghb_instance_status_t *status) else { status_str= g_strdup_printf( - "Encoding: %s%s%.2f %%" - " (ETA %02dh%02dm%02ds)", + _("Encoding: %s%s%.2f %%" + " (ETA %02dh%02dm%02ds)"), job_str, task_str, 100.0 * status->progress, status->hours, status->minutes, status->seconds ); @@ -2757,7 +2784,7 @@ working_status_string(signal_user_data_t *ud, ghb_instance_status_t *status) else { status_str= g_strdup_printf( - "Encoding: %s%s%.2f %%", + _("Encoding: %s%s%.2f %%"), job_str, task_str, 100.0 * status->progress ); } @@ -2778,18 +2805,18 @@ searching_status_string(signal_user_data_t *ud, ghb_instance_status_t *status) index = find_queue_job(ud->queue, status->unique_id, &js); if (qcount > 1) { - job_str = g_strdup_printf("job %d of %d, ", index+1, qcount); + job_str = g_strdup_printf(_("job %d of %d, "), index+1, qcount); } else { job_str = g_strdup(""); } - task_str = g_strdup_printf("Searching for start time, "); + task_str = g_strdup_printf(_("Searching for start time, ")); if(status->seconds > -1) { status_str= g_strdup_printf( - "Encoding: %s%s%.2f %%" - " (ETA %02dh%02dm%02ds)", + _("Encoding: %s%s%.2f %%" + " (ETA %02dh%02dm%02ds)"), job_str, task_str, 100.0 * status->progress, status->hours, status->minutes, status->seconds ); @@ -2797,7 +2824,7 @@ searching_status_string(signal_user_data_t *ud, ghb_instance_status_t *status) else { status_str= g_strdup_printf( - "Encoding: %s%s%.2f %%", + _("Encoding: %s%s%.2f %%"), job_str, task_str, 100.0 * status->progress ); } @@ -2856,16 +2883,16 @@ ghb_backend_events(signal_user_data_t *ud) if (status.scan.title_cur == 0) { - status_str = g_strdup ("Scanning..."); + status_str = g_strdup (_("Scanning...")); } else { if (status.scan.preview_cur == 0) - status_str = g_strdup_printf("Scanning title %d of %d...", + status_str = g_strdup_printf(_("Scanning title %d of %d..."), status.scan.title_cur, status.scan.title_count ); else status_str = g_strdup_printf( - "Scanning title %d of %d preview %d...", + _("Scanning title %d of %d preview %d..."), status.scan.title_cur, status.scan.title_count, status.scan.preview_cur); @@ -2888,8 +2915,8 @@ ghb_backend_events(signal_user_data_t *ud) widget = GHB_WIDGET(ud->builder, "sourcetoolbutton"); gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(widget), "hb-source"); - gtk_tool_button_set_label(GTK_TOOL_BUTTON(widget), "Source"); - gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(widget), "Choose Video Source"); + gtk_tool_button_set_label(GTK_TOOL_BUTTON(widget), _("Source")); + gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(widget), _("Choose Video Source")); action = GHB_ACTION(ud->builder, "source_action"); gtk_action_set_sensitive(action, TRUE); @@ -2917,7 +2944,7 @@ ghb_backend_events(signal_user_data_t *ud) hb_title_t * title = ghb_get_title_info(titleindex); if (title == NULL) { - gtk_label_set_text(label, "None"); + gtk_label_set_text(label, _("None")); } ghb_clear_scan_state(GHB_STATE_SCANDONE); if (ghb_queue_edit_settings) @@ -2935,7 +2962,7 @@ ghb_backend_events(signal_user_data_t *ud) { // This needs to be in scanning and working since scanning // happens fast enough that it can be missed - gtk_label_set_text (work_status, "Scanning ..."); + gtk_label_set_text (work_status, _("Scanning ...")); gtk_progress_bar_set_fraction (progress, 0); } else if (status.queue.state & GHB_STATE_SCANDONE) @@ -2947,7 +2974,7 @@ ghb_backend_events(signal_user_data_t *ud) } else if (status.queue.state & GHB_STATE_PAUSED) { - gtk_label_set_text (work_status, "Paused"); + gtk_label_set_text (work_status, _("Paused")); } else if (status.queue.state & GHB_STATE_SEARCHING) { @@ -3059,7 +3086,7 @@ ghb_backend_events(signal_user_data_t *ud) switch( status.queue.error ) { case GHB_ERROR_NONE: - gtk_label_set_text (work_status, "Encode Done!"); + gtk_label_set_text (work_status, _("Encode Done!")); qstatus = GHB_QUEUE_DONE; if (js != NULL) { @@ -3073,7 +3100,7 @@ ghb_backend_events(signal_user_data_t *ud) } break; case GHB_ERROR_CANCELED: - gtk_label_set_text (work_status, "Encode Canceled."); + gtk_label_set_text (work_status, _("Encode Canceled.")); qstatus = GHB_QUEUE_CANCELED; if (js != NULL) { @@ -3087,7 +3114,7 @@ ghb_backend_events(signal_user_data_t *ud) } break; default: - gtk_label_set_text (work_status, "Encode Failed."); + gtk_label_set_text (work_status, _("Encode Failed.")); qstatus = GHB_QUEUE_CANCELED; if (js != NULL) { @@ -3133,7 +3160,7 @@ ghb_backend_events(signal_user_data_t *ud) } else if (status.queue.state & GHB_STATE_MUXING) { - gtk_label_set_text (work_status, "Muxing: This may take a while..."); + gtk_label_set_text (work_status, _("Muxing: This may take a while...")); } if (status.scan.state & GHB_STATE_WORKING) @@ -3182,7 +3209,7 @@ status_icon_query_tooltip_cb( else if (status.queue.state & GHB_STATE_SEARCHING) status_str = searching_status_string(ud, &status.queue); else if (status.queue.state & GHB_STATE_WORKDONE) - status_str = g_strdup("Encode Complete"); + status_str = g_strdup(_("Encode Complete")); else status_str = g_strdup("HandBrake"); @@ -3365,19 +3392,6 @@ ghb_log_cb(GIOChannel *source, GIOCondition cond, gpointer data) return TRUE; } -static void -set_visible(GtkWidget *widget, gboolean visible) -{ - if (visible) - { - gtk_widget_show_now(widget); - } - else - { - gtk_widget_hide(widget); - } -} - G_MODULE_EXPORT void show_activity_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud) { @@ -4855,7 +4869,7 @@ tweak_setting_cb( { gchar *message; message = g_strdup_printf( - "Invalid Settings:\n%s", + _("Invalid Settings:\n%s"), tweak); ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL); g_free(message); @@ -4898,7 +4912,7 @@ format_deblock_cb(GtkScale *scale, gdouble val, signal_user_data_t *ud) { if (val < 5.0) { - return g_strdup_printf("Off"); + return g_strdup_printf(_("Off")); } else { @@ -4916,7 +4930,7 @@ format_vquality_cb(GtkScale *scale, gdouble val, signal_user_data_t *ud) { if (val == 0.0) { - return g_strdup_printf("RF: %.4g (Warning: lossless)", val); + return g_strdup_printf(_("RF: %.4g (Warning: lossless)"), val); } else { @@ -4967,7 +4981,7 @@ process_appcast(signal_user_data_t *ud) { goto done; } - msg = g_strdup_printf("HandBrake %s/%s is now available (you have %s/%d).", + msg = g_strdup_printf(_("HandBrake %s/%s is now available (you have %s/%d)."), version, build, hb_get_version(NULL), hb_get_build(NULL)); label = GHB_WIDGET(ud->builder, "update_message"); gtk_label_set_text(GTK_LABEL(label), msg); @@ -5208,8 +5222,8 @@ ghb_notify_done(signal_user_data_t *ud) #if !defined(_WIN32) NotifyNotification *notification; notification = notify_notification_new( - "Encode Complete", - "Put down that cocktail, Your HandBrake queue is done!", + _("Encode Complete"), + _("Put down that cocktail, Your HandBrake queue is done!"), NULL #if NOTIFY_CHECK_VERSION (0, 7, 0) ); @@ -5233,9 +5247,9 @@ ghb_notify_done(signal_user_data_t *ud) if (ghb_can_shutdown_gsm()) { ghb_countdown_dialog(GTK_MESSAGE_WARNING, - "Your encode is complete.", - "Shutting down the computer", - "Cancel", (GSourceFunc)shutdown_cb, ud, 60); + _("Your encode is complete."), + _("Shutting down the computer"), + _("Cancel"), (GSourceFunc)shutdown_cb, ud, 60); } } if (ghb_settings_combo_int(ud->settings, "WhenComplete") == 2) @@ -5243,17 +5257,17 @@ ghb_notify_done(signal_user_data_t *ud) if (ghb_can_suspend_gpm()) { ghb_countdown_dialog(GTK_MESSAGE_WARNING, - "Your encode is complete.", - "Putting computer to sleep", - "Cancel", (GSourceFunc)suspend_cb, ud, 60); + _("Your encode is complete."), + _("Putting computer to sleep"), + _("Cancel"), (GSourceFunc)suspend_cb, ud, 60); } } if (ghb_settings_combo_int(ud->settings, "WhenComplete") == 4) { ghb_countdown_dialog(GTK_MESSAGE_WARNING, - "Your encode is complete.", - "Quiting Handbrake", - "Cancel", (GSourceFunc)quit_cb, ud, 60); + _("Your encode is complete."), + _("Quiting Handbrake"), + _("Cancel"), (GSourceFunc)quit_cb, ud, 60); } } diff --git a/gtk/src/ghb.desktop b/gtk/src/ghb.desktop index 3583fdd6c..e029bdc37 100644 --- a/gtk/src/ghb.desktop +++ b/gtk/src/ghb.desktop @@ -2,7 +2,7 @@ Name=HandBrake GenericName=Media Transcoder Comment=Transcodes DVD, Bluray, and other media -Exec=ghb +Exec=ghb %f Icon=hb-icon Terminal=false Type=Application diff --git a/gtk/src/ghb.ui b/gtk/src/ghb.ui index ba8f46856..740ab38a6 100644 --- a/gtk/src/ghb.ui +++ b/gtk/src/ghb.ui @@ -411,7 +411,7 @@ This setting allows you to synchronize the files.</property> <object class="GtkAction" id="source_action"> <property name="stock_id">gtk-open</property> <property name="name">source_action</property> - <property name="label">_Source</property> + <property name="label" translatable="yes">_Source</property> <signal handler="source_button_clicked_cb" name="activate"/> </object> </child> @@ -419,7 +419,7 @@ This setting allows you to synchronize the files.</property> <object class="GtkAction" id="source_single_action"> <property name="stock_id">gtk-open</property> <property name="name">source_single_action</property> - <property name="label">Single _Title</property> + <property name="label" translatable="yes">Single _Title</property> <signal handler="single_title_source_cb" name="activate"/> </object> </child> @@ -427,7 +427,7 @@ This setting allows you to synchronize the files.</property> <object class="GtkAction" id="destination1"> <property name="stock_id">gtk-save-as</property> <property name="name">destination1</property> - <property name="label">_Destination</property> + <property name="label" translatable="yes">_Destination</property> <signal handler="destination_browse_clicked_cb" name="activate"/> </object> </child> @@ -456,7 +456,7 @@ This setting allows you to synchronize the files.</property> <property name="sensitive">False</property> <property name="icon-name">hb-add-queue</property> <property name="name">queue_add_menu</property> - <property name="label">_Add Queue</property> + <property name="label" translatable="yes">_Add Queue</property> <signal handler="queue_add_clicked_cb" name="activate"/> </object> </child> @@ -465,7 +465,7 @@ This setting allows you to synchronize the files.</property> <property name="sensitive">False</property> <property name="icon-name">hb-add-queue</property> <property name="name">queue_add_all_menu</property> - <property name="label">Add A_ll Queue</property> + <property name="label" translatable="yes">Add A_ll Queue</property> <signal handler="queue_add_all_clicked_cb" name="activate"/> </object> </child> @@ -474,7 +474,7 @@ This setting allows you to synchronize the files.</property> <property name="sensitive">False</property> <property name="icon-name">hb-start</property> <property name="name">queue_start_menu</property> - <property name="label">_Start Queue</property> + <property name="label" translatable="yes">_Start Queue</property> <signal handler="queue_start_clicked_cb" name="activate"/> </object> </child> @@ -604,7 +604,7 @@ This setting allows you to synchronize the files.</property> <object class="GtkMenu" id="presets_menu"> <child> <object class="GtkImageMenuItem" id="presets_default"> - <property name="label">_Make Default</property> + <property name="label" translatable="yes">_Make Default</property> <property name="image">image12</property> <property name="visible">True</property> <property name="use_underline">True</property> @@ -1192,7 +1192,7 @@ This setting allows you to synchronize the files.</property> </object> <packing> <property name="x_options">GTK_FILL</property> - <property name="y_options">GTK_FILL</property> + <property name="y_options"></property> </packing> </child> <child> @@ -2551,7 +2551,7 @@ This setting allows you to synchronize the files.</property> <property name="visible">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="expanded">False</property> - <property name="label">Advanced</property> + <property name="label" translatable="yes">Advanced</property> <child> <object class="GtkVBox" id="vbox44"> <property name="visible">True</property> @@ -3274,7 +3274,7 @@ This setting allows you to synchronize the files.</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="tooltip-text" translatable="yes">Add new subtitle to the list</property> <property name="relief">GTK_RELIEF_NONE</property> - <property name="label">Subtitle</property> + <property name="label" translatable="yes">Subtitle</property> <property name="image">subtitle_add_image</property> <signal handler="subtitle_add_clicked_cb" name="clicked"/> </object> @@ -3290,7 +3290,7 @@ This setting allows you to synchronize the files.</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="tooltip-text" translatable="yes">Add new SRT subtitle to the list</property> <property name="relief">GTK_RELIEF_NONE</property> - <property name="label">Import SRT</property> + <property name="label" translatable="yes">Import SRT</property> <property name="image">srt_add_image</property> <signal handler="srt_add_clicked_cb" name="clicked"/> </object> diff --git a/gtk/src/hb-backend.c b/gtk/src/hb-backend.c index ace8291b4..ec6379eb2 100644 --- a/gtk/src/hb-backend.c +++ b/gtk/src/hb-backend.c @@ -27,6 +27,7 @@ #include "hb.h" #include "ghbcompat.h" #include <glib/gstdio.h> +#include <glib/gi18n.h> #include "hb-backend.h" #include "settings.h" #include "callbacks.h" @@ -72,9 +73,9 @@ index_str_init(gint max_index) static options_map_t d_point_to_point_opts[] = { - {"Chapters:", "chapter", 0, "0"}, - {"Seconds:", "time", 1, "1"}, - {"Frames:", "frame", 2, "2"}, + {N_("Chapters:"), "chapter", 0, "0"}, + {N_("Seconds:"), "time", 1, "1"}, + {N_("Frames:"), "frame", 2, "2"}, }; combo_opts_t point_to_point_opts = { @@ -84,11 +85,11 @@ combo_opts_t point_to_point_opts = static options_map_t d_when_complete_opts[] = { - {"Do Nothing", "nothing", 0, "0"}, - {"Show Notification", "notify", 1, "1"}, - {"Quit Handbrake", "quit", 4, "4"}, - {"Put Computer To Sleep", "sleep", 2, "2"}, - {"Shutdown Computer", "shutdown", 3, "3"}, + {N_("Do Nothing"), "nothing", 0, "0"}, + {N_("Show Notification"), "notify", 1, "1"}, + {N_("Quit Handbrake"), "quit", 4, "4"}, + {N_("Put Computer To Sleep"), "sleep", 2, "2"}, + {N_("Shutdown Computer"), "shutdown", 3, "3"}, }; combo_opts_t when_complete_opts = { @@ -98,10 +99,10 @@ combo_opts_t when_complete_opts = static options_map_t d_par_opts[] = { - {"Off", "0", 0, "0"}, - {"Strict", "1", 1, "1"}, - {"Loose", "2", 2, "2"}, - {"Custom", "3", 3, "3"}, + {N_("Off"), "0", 0, "0"}, + {N_("Strict"), "1", 1, "1"}, + {N_("Loose"), "2", 2, "2"}, + {N_("Custom"), "3", 3, "3"}, }; combo_opts_t par_opts = { @@ -136,10 +137,10 @@ combo_opts_t logging_opts = static options_map_t d_log_longevity_opts[] = { - {"Week", "week", 7, "7"}, - {"Month", "month", 30, "30"}, - {"Year", "year", 365, "365"}, - {"Immortal", "immortal", 366, "366"}, + {N_("Week"), "week", 7, "7"}, + {N_("Month"), "month", 30, "30"}, + {N_("Year"), "year", 365, "365"}, + {N_("Immortal"), "immortal", 366, "366"}, }; combo_opts_t log_longevity_opts = { @@ -149,10 +150,10 @@ combo_opts_t log_longevity_opts = static options_map_t d_appcast_update_opts[] = { - {"Never", "never", 0, "never"}, - {"Daily", "daily", 1, "daily"}, - {"Weekly", "weekly", 2, "weekly"}, - {"Monthly", "monthly", 3, "monthly"}, + {N_("Never"), "never", 0, "never"}, + {N_("Daily"), "daily", 1, "daily"}, + {N_("Weekly"), "weekly", 2, "weekly"}, + {N_("Monthly"), "monthly", 3, "monthly"}, }; combo_opts_t appcast_update_opts = { @@ -175,9 +176,9 @@ combo_opts_t vqual_granularity_opts = static options_map_t d_detel_opts[] = { - {"Off", "off", 0, ""}, - {"Custom", "custom", 1, ""}, - {"Default","default",2, NULL}, + {N_("Off"), "off", 0, ""}, + {N_("Custom"), "custom", 1, ""}, + {N_("Default"),"default",2, NULL}, }; combo_opts_t detel_opts = { @@ -187,11 +188,11 @@ combo_opts_t detel_opts = static options_map_t d_decomb_opts[] = { - {"Off", "off", 0, ""}, - {"Custom", "custom", 1, ""}, - {"Default","default",2, NULL}, - {"Fast", "fast", 3, "7:2:6:9:1:80"}, - {"Bob", "bob", 4, "455"}, + {N_("Off"), "off", 0, ""}, + {N_("Custom"), "custom", 1, ""}, + {N_("Default"),"default",2, NULL}, + {N_("Fast"), "fast", 3, "7:2:6:9:1:80"}, + {N_("Bob"), "bob", 4, "455"}, }; combo_opts_t decomb_opts = { @@ -201,12 +202,12 @@ combo_opts_t decomb_opts = static options_map_t d_deint_opts[] = { - {"Off", "off", 0, ""}, - {"Custom", "custom", 1, ""}, - {"Fast", "fast", 2, "0:-1:-1:0:1"}, - {"Slow", "slow", 3, "1:-1:-1:0:1"}, - {"Slower", "slower", 4, "3:-1:-1:0:1"}, - {"Bob", "bob", 5, "15:-1:-1:0:1"}, + {N_("Off"), "off", 0, ""}, + {N_("Custom"), "custom", 1, ""}, + {N_("Fast"), "fast", 2, "0:-1:-1:0:1"}, + {N_("Slow"), "slow", 3, "1:-1:-1:0:1"}, + {N_("Slower"), "slower", 4, "3:-1:-1:0:1"}, + {N_("Bob"), "bob", 5, "15:-1:-1:0:1"}, }; combo_opts_t deint_opts = { @@ -216,11 +217,11 @@ combo_opts_t deint_opts = static options_map_t d_denoise_opts[] = { - {"Off", "off", 0, ""}, - {"Custom", "custom", 1, ""}, - {"Weak", "weak", 2, "2:1:2:3"}, - {"Medium", "medium", 3, "3:2:2:3"}, - {"Strong", "strong", 4, "7:7:5:5"}, + {N_("Off"), "off", 0, ""}, + {N_("Custom"), "custom", 1, ""}, + {N_("Weak"), "weak", 2, "2:1:2:3"}, + {N_("Medium"), "medium", 3, "3:2:2:3"}, + {N_("Strong"), "strong", 4, "7:7:5:5"}, }; combo_opts_t denoise_opts = { @@ -230,10 +231,10 @@ combo_opts_t denoise_opts = static options_map_t d_direct_opts[] = { - {"None", "none", 0, "none"}, - {"Spatial", "spatial", 1, "spatial"}, - {"Temporal", "temporal", 2, "temporal"}, - {"Automatic", "auto", 3, "auto"}, + {N_("None"), "none", 0, "none"}, + {N_("Spatial"), "spatial", 1, "spatial"}, + {N_("Temporal"), "temporal", 2, "temporal"}, + {N_("Automatic"), "auto", 3, "auto"}, }; combo_opts_t direct_opts = { @@ -243,9 +244,9 @@ combo_opts_t direct_opts = static options_map_t d_badapt_opts[] = { - {"Off", "0", 0, "0"}, - {"Fast", "1", 1, "1"}, - {"Optimal", "2", 2, "2"}, + {N_("Off"), "0", 0, "0"}, + {N_("Fast"), "1", 1, "1"}, + {N_("Optimal"), "2", 2, "2"}, }; combo_opts_t badapt_opts = { @@ -255,9 +256,9 @@ combo_opts_t badapt_opts = static options_map_t d_bpyramid_opts[] = { - {"Off", "none", 0, "none"}, - {"Strict", "strict", 1, "strict"}, - {"Normal", "normal", 2, "normal"}, + {N_("Off"), "none", 0, "none"}, + {N_("Strict"), "strict", 1, "strict"}, + {N_("Normal"), "normal", 2, "normal"}, }; combo_opts_t bpyramid_opts = { @@ -267,9 +268,9 @@ combo_opts_t bpyramid_opts = static options_map_t d_weightp_opts[] = { - {"Off", "0", 0, "0"}, - {"Simple", "1", 1, "1"}, - {"Smart", "2", 2, "2"}, + {N_("Off"), "0", 0, "0"}, + {N_("Simple"), "1", 1, "1"}, + {N_("Smart"), "2", 2, "2"}, }; combo_opts_t weightp_opts = { @@ -279,11 +280,11 @@ combo_opts_t weightp_opts = static options_map_t d_me_opts[] = { - {"Diamond", "dia", 0, "dia"}, - {"Hexagon", "hex", 1, "hex"}, - {"Uneven Multi-Hexagon", "umh", 2, "umh"}, - {"Exhaustive", "esa", 3, "esa"}, - {"Hadamard Exhaustive", "tesa", 4, "tesa"}, + {N_("Diamond"), "dia", 0, "dia"}, + {N_("Hexagon"), "hex", 1, "hex"}, + {N_("Uneven Multi-Hexagon"), "umh", 2, "umh"}, + {N_("Exhaustive"), "esa", 3, "esa"}, + {N_("Hadamard Exhaustive"), "tesa", 4, "tesa"}, }; combo_opts_t me_opts = { @@ -293,18 +294,18 @@ combo_opts_t me_opts = static options_map_t d_subme_opts[] = { - {"0: SAD, no subpel", "0", 0, "0"}, - {"1: SAD, qpel", "1", 1, "1"}, - {"2: SATD, qpel", "2", 2, "2"}, - {"3: SATD: multi-qpel", "3", 3, "3"}, - {"4: SATD, qpel on all", "4", 4, "4"}, - {"5: SATD, multi-qpel on all", "5", 5, "5"}, - {"6: RD in I/P-frames", "6", 6, "6"}, - {"7: RD in all frames", "7", 7, "7"}, - {"8: RD refine in I/P-frames", "8", 8, "8"}, - {"9: RD refine in all frames", "9", 9, "9"}, - {"10: QPRD in all frames", "10", 10, "10"}, - {"11: No early terminations in analysis", "11", 11, "11"}, + {N_("0: SAD, no subpel"), "0", 0, "0"}, + {N_("1: SAD, qpel"), "1", 1, "1"}, + {N_("2: SATD, qpel"), "2", 2, "2"}, + {N_("3: SATD: multi-qpel"), "3", 3, "3"}, + {N_("4: SATD, qpel on all"), "4", 4, "4"}, + {N_("5: SATD, multi-qpel on all"), "5", 5, "5"}, + {N_("6: RD in I/P-frames"), "6", 6, "6"}, + {N_("7: RD in all frames"), "7", 7, "7"}, + {N_("8: RD refine in I/P-frames"), "8", 8, "8"}, + {N_("9: RD refine in all frames"), "9", 9, "9"}, + {N_("10: QPRD in all frames"), "10", 10, "10"}, + {N_("11: No early terminations in analysis"), "11", 11, "11"}, }; combo_opts_t subme_opts = { @@ -314,11 +315,11 @@ combo_opts_t subme_opts = static options_map_t d_analyse_opts[] = { - {"Most", "p8x8,b8x8,i8x8,i4x4", 0, "p8x8,b8x8,i8x8,i4x4"}, - {"None", "none", 1, "none"}, - {"Some", "i4x4,i8x8", 2, "i4x4,i8x8"}, - {"All", "all", 3, "all"}, - {"Custom", "custom", 4, "all"}, + {N_("Most"), "p8x8,b8x8,i8x8,i4x4", 0, "p8x8,b8x8,i8x8,i4x4"}, + {N_("None"), "none", 1, "none"}, + {N_("Some"), "i4x4,i8x8", 2, "i4x4,i8x8"}, + {N_("All"), "all", 3, "all"}, + {N_("Custom"), "custom", 4, "all"}, }; combo_opts_t analyse_opts = { @@ -328,9 +329,9 @@ combo_opts_t analyse_opts = static options_map_t d_trellis_opts[] = { - {"Off", "0", 0, "0"}, - {"Encode only", "1", 1, "1"}, - {"Always", "2", 2, "2"}, + {N_("Off"), "0", 0, "0"}, + {N_("Encode only"), "1", 1, "1"}, + {N_("Always"), "2", 2, "2"}, }; combo_opts_t trellis_opts = { @@ -1408,44 +1409,6 @@ ghb_subtitle_track_source(GValue *settings, gint track) return VOBSUB; } -const char* -ghb_subtitle_track_source_name(GValue *settings, gint track) -{ - gint titleindex; - const gchar * name = "Unknown"; - - if (track == -2) - { - name = "SRT"; - goto done; - } - if (track == -1) - { - name = "Bitmap"; - goto done; - } - - titleindex = ghb_settings_combo_int(settings, "title"); - if (titleindex < 0) - goto done; - - hb_title_t * title; - hb_subtitle_t * sub; - - title = ghb_get_title_info( titleindex ); - if (title == NULL) - goto done; - - sub = hb_list_item( title->list_subtitle, track); - if (sub != NULL) - { - name = hb_subsource_name(sub->source); - } - -done: - return name; -} - const gchar* ghb_subtitle_track_lang(GValue *settings, gint track) { @@ -1715,13 +1678,15 @@ audio_samplerate_opts_set(GtkBuilder *builder, const gchar *name) gtk_list_store_clear(store); // Add an item for "Same As Source" gtk_list_store_append(store, &iter); + str = g_strdup_printf("<small>%s</small>", _("Same as source")); gtk_list_store_set(store, &iter, - 0, "<small>Same as source</small>", + 0, str, 1, TRUE, 2, "source", 3, 0.0, 4, "source", -1); + g_free(str); const hb_rate_t *rate; for (rate = hb_audio_samplerate_get_next(NULL); rate != NULL; @@ -1752,7 +1717,7 @@ video_framerate_opts_set(GtkBuilder *builder, const gchar *name) // Add an item for "Same As Source" gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, - 0, "Same as source", + 0, _("Same as source"), 1, TRUE, 2, "source", 3, 0.0, @@ -1767,15 +1732,15 @@ video_framerate_opts_set(GtkBuilder *builder, const gchar *name) gchar *option; if (strcmp(rate->name, "23.976") == 0) { - desc = "(NTSC Film)"; + desc = _("(NTSC Film)"); } else if (strcmp(rate->name, "25") == 0) { - desc = "(PAL Film/Video)"; + desc = _("(PAL Film/Video)"); } else if (strcmp(rate->name, "29.97") == 0) { - desc = "(NTSC Video)"; + desc = _("(NTSC Video)"); } option = g_strdup_printf ("%s %s", rate->name, desc); gtk_list_store_append(store, &iter); @@ -2019,7 +1984,7 @@ title_opts_set(GtkBuilder *builder, const gchar *name) // No titles. Fill in a default. gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, - 0, "No Titles", + 0, _("No Titles"), 1, TRUE, 2, "none", 3, -1.0, @@ -2114,7 +2079,7 @@ x264_tune_opts_set(GtkBuilder *builder, const gchar *name) gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, - 0, "None", + 0, _("None"), 1, TRUE, 2, "none", 3, (gdouble)0, @@ -2263,13 +2228,15 @@ audio_track_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex) { // No audio. set some default gtk_list_store_append(store, &iter); + str = g_strdup_printf("<small>%s</small>", _("No Audio")); gtk_list_store_set(store, &iter, - 0, "<small>No Audio</small>", + 0, str, 1, TRUE, 2, "none", 3, -1.0, 4, "none", -1); + g_free(str); audio_track_opts.map[0].option = g_strdup("No Audio"); audio_track_opts.map[0].shortOpt = "none"; audio_track_opts.map[0].ivalue = -1; @@ -2351,7 +2318,7 @@ subtitle_track_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex) } gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, - 0, "Foreign Audio Search", + 0, _("Foreign Audio Search"), 1, TRUE, 2, "-1", 3, -1.0, @@ -2815,7 +2782,7 @@ generic_opts_set(GtkBuilder *builder, const gchar *name, combo_opts_t *opts) { gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, - 0, opts->map[ii].option, + 0, _(opts->map[ii].option), 1, TRUE, 2, opts->map[ii].shortOpt, 3, opts->map[ii].ivalue, @@ -2839,7 +2806,7 @@ small_opts_set(GtkBuilder *builder, const gchar *name, combo_opts_t *opts) for (ii = 0; ii < opts->count; ii++) { gtk_list_store_append(store, &iter); - str = g_strdup_printf("<small>%s</small>", opts->map[ii].option); + str = g_strdup_printf("<small>%s</small>", _(opts->map[ii].option)); gtk_list_store_set(store, &iter, 0, str, 1, TRUE, @@ -4362,9 +4329,9 @@ ghb_validate_filters(GValue *settings) if (!ghb_validate_filter_string(str, -1)) { message = g_strdup_printf( - "Invalid Deinterlace Settings:\n\n%s\n", + _("Invalid Deinterlace Settings:\n\n%s\n"), str); - ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL); + ghb_message_dialog(GTK_MESSAGE_ERROR, message, _("Cancel"), NULL); g_free(message); g_free(str); return FALSE; @@ -4379,9 +4346,9 @@ ghb_validate_filters(GValue *settings) if (!ghb_validate_filter_string(str, -1)) { message = g_strdup_printf( - "Invalid Detelecine Settings:\n\n%s\n", + _("Invalid Detelecine Settings:\n\n%s\n"), str); - ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL); + ghb_message_dialog(GTK_MESSAGE_ERROR, message, _("Cancel"), NULL); g_free(message); g_free(str); return FALSE; @@ -4396,9 +4363,9 @@ ghb_validate_filters(GValue *settings) if (!ghb_validate_filter_string(str, -1)) { message = g_strdup_printf( - "Invalid Decomb Settings:\n\n%s\n", + N_("Invalid Decomb Settings:\n\n%s\n"), str); - ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL); + ghb_message_dialog(GTK_MESSAGE_ERROR, message, _("Cancel"), NULL); g_free(message); g_free(str); return FALSE; @@ -4413,9 +4380,9 @@ ghb_validate_filters(GValue *settings) if (!ghb_validate_filter_string(str, -1)) { message = g_strdup_printf( - "Invalid Denoise Settings:\n\n%s\n", + _("Invalid Denoise Settings:\n\n%s\n"), str); - ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL); + ghb_message_dialog(GTK_MESSAGE_ERROR, message, _("Cancel"), NULL); g_free(str); g_free(message); return FALSE; @@ -4433,14 +4400,14 @@ ghb_validate_video(GValue *settings) mux = ghb_settings_combo_int(settings, "FileFormat"); vcodec = ghb_settings_combo_int(settings, "VideoEncoder"); - if ((mux == HB_MUX_MP4) && (vcodec == HB_VCODEC_THEORA)) + if ((mux & HB_MUX_MASK_MP4) && (vcodec == HB_VCODEC_THEORA)) { // mp4/theora combination is not supported. message = g_strdup_printf( - "Theora is not supported in the MP4 container.\n\n" + _("Theora is not supported in the MP4 container.\n\n" "You should choose a different video codec or container.\n" - "If you continue, FFMPEG will be chosen for you."); - if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue")) + "If you continue, FFMPEG will be chosen for you.")); + if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, _("Cancel"), _("Continue"))) { g_free(message); return FALSE; @@ -4484,10 +4451,10 @@ ghb_validate_subtitles(GValue *settings) // MP4 can only handle burned vobsubs. make sure there isn't // already something burned in the list message = g_strdup_printf( - "Only one subtitle may be burned into the video.\n\n" + _("Only one subtitle may be burned into the video.\n\n" "You should change your subtitle selections.\n" - "If you continue, some subtitles will be lost."); - if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue")) + "If you continue, some subtitles will be lost.")); + if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, _("Cancel"), _("Continue"))) { g_free(message); return FALSE; @@ -4507,11 +4474,11 @@ ghb_validate_subtitles(GValue *settings) if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) { message = g_strdup_printf( - "Srt file does not exist or not a regular file.\n\n" + _("Srt file does not exist or not a regular file.\n\n" "You should choose a valid file.\n" - "If you continue, this subtitle will be ignored."); + "If you continue, this subtitle will be ignored.")); if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, - "Cancel", "Continue")) + _("Cancel"), _("Continue"))) { g_free(message); return FALSE; @@ -4567,10 +4534,10 @@ ghb_validate_audio(GValue *settings) { // Not supported. AC3 is passthrough only, so input must be AC3 message = g_strdup_printf( - "The source does not support Pass-Thru.\n\n" + _("The source does not support Pass-Thru.\n\n" "You should choose a different audio codec.\n" - "If you continue, one will be chosen for you."); - if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue")) + "If you continue, one will be chosen for you.")); + if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, _("Cancel"), _("Continue"))) { g_free(message); return FALSE; @@ -4581,7 +4548,7 @@ ghb_validate_audio(GValue *settings) { codec = HB_ACODEC_AC3; } - else if (mux == HB_MUX_MKV) + else if (mux & HB_MUX_MASK_MKV) { codec = HB_ACODEC_LAME; } @@ -4594,7 +4561,7 @@ ghb_validate_audio(GValue *settings) } gchar *a_unsup = NULL; gchar *mux_s = NULL; - if (mux == HB_MUX_MP4) + if (mux & HB_MUX_MASK_MP4) { mux_s = "MP4"; // mp4/vorbis|DTS combination is not supported. @@ -4607,10 +4574,10 @@ ghb_validate_audio(GValue *settings) if (a_unsup) { message = g_strdup_printf( - "%s is not supported in the %s container.\n\n" + _("%s is not supported in the %s container.\n\n" "You should choose a different audio codec.\n" - "If you continue, one will be chosen for you.", a_unsup, mux_s); - if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue")) + "If you continue, one will be chosen for you."), a_unsup, mux_s); + if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, _("Cancel"), _("Continue"))) { g_free(message); return FALSE; @@ -4632,10 +4599,10 @@ ghb_validate_audio(GValue *settings) if (mix_unsup) { message = g_strdup_printf( - "The source audio does not support %s mixdown.\n\n" + _("The source audio does not support %s mixdown.\n\n" "You should choose a different mixdown.\n" - "If you continue, one will be chosen for you.", mix_unsup); - if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue")) + "If you continue, one will be chosen for you."), mix_unsup); + if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, _("Cancel"), _("Continue"))) { g_free(message); return FALSE; @@ -4692,13 +4659,13 @@ ghb_validate_vquality(GValue *settings) if (vcodec == HB_VCODEC_X264 && vquality == 0.0) { message = g_strdup_printf( - "Warning: lossless h.264 selected\n\n" + _("Warning: lossless h.264 selected\n\n" "Lossless h.264 is not well supported by\n" "many players and editors.\n\n" "It will produce enormous output files.\n\n" - "Are you sure you wish to use this setting?"); + "Are you sure you wish to use this setting?")); if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, - "Cancel", "Continue")) + _("Cancel"), _("Continue"))) { g_free(message); return FALSE; @@ -4709,12 +4676,12 @@ ghb_validate_vquality(GValue *settings) else if (vquality < min || vquality > max) { message = g_strdup_printf( - "Interesting video quality choice: %d\n\n" + _("Interesting video quality choice: %d\n\n" "Typical values range from %d to %d.\n\n" - "Are you sure you wish to use this setting?", + "Are you sure you wish to use this setting?"), (gint)vquality, min, max); if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, - "Cancel", "Continue")) + _("Cancel"), _("Continue"))) { g_free(message); return FALSE; @@ -4761,7 +4728,7 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex) } job->mux = ghb_settings_combo_int(js, "FileFormat"); - if (job->mux == HB_MUX_MP4) + if (job->mux & HB_MUX_MASK_MP4) { job->largeFileSize = ghb_settings_get_boolean(js, "Mp4LargeFile"); job->mp4_optimize = ghb_settings_get_boolean(js, "Mp4HttpOptimize"); @@ -4957,12 +4924,12 @@ add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex) } job->vcodec = ghb_settings_combo_int(js, "VideoEncoder"); - if ((job->mux == HB_MUX_MP4 ) && (job->vcodec == HB_VCODEC_THEORA)) + if ((job->mux & HB_MUX_MASK_MP4 ) && (job->vcodec == HB_VCODEC_THEORA)) { // mp4/theora combination is not supported. job->vcodec = HB_VCODEC_FFMPEG_MPEG4; } - if ((job->vcodec == HB_VCODEC_X264) && (job->mux == HB_MUX_MP4)) + if ((job->vcodec == HB_VCODEC_X264) && (job->mux & HB_MUX_MASK_MP4)) { job->ipod_atom = ghb_settings_get_boolean(js, "Mp4iPodCompatible"); } diff --git a/gtk/src/hb-backend.h b/gtk/src/hb-backend.h index 03d0ce4ed..68a91cf01 100644 --- a/gtk/src/hb-backend.h +++ b/gtk/src/hb-backend.h @@ -141,7 +141,6 @@ gchar* ghb_dvd_volname(const gchar *device); gint ghb_get_title_number(gint titleindex); int ghb_get_title_count(); gint ghb_subtitle_track_source(GValue *settings, gint track); -const char* ghb_subtitle_track_source_name(GValue *settings, gint track); const gchar* ghb_subtitle_track_lang(GValue *settings, gint track); gboolean ghb_validate_vquality(GValue *settings); diff --git a/gtk/src/main.c b/gtk/src/main.c index b656f7812..b23936d34 100644 --- a/gtk/src/main.c +++ b/gtk/src/main.c @@ -52,6 +52,7 @@ #endif #include <glib/gstdio.h> +#include <glib/gi18n.h> #include <gio/gio.h> #include "hb.h" #include "renderer_button.h" @@ -73,16 +74,7 @@ /* * Standard gettext macros. */ -#ifdef ENABLE_NLS -# include <libintl.h> -# undef _ -# define _(String) dgettext(PACKAGE, String) -# ifdef gettext_noop -# define N_(String) gettext_noop(String) -# else -# define N_(String) (String) -# endif -#else +#ifndef ENABLE_NLS # define textdomain(String) (String) # define gettext(String) (String) # define dgettext(Domain,Message) (Message) @@ -688,9 +680,9 @@ static gboolean ghb_debug = FALSE; static GOptionEntry entries[] = { - { "device", 'd', 0, G_OPTION_ARG_FILENAME, &dvd_device, "The device or file to encode", NULL }, - { "preset", 'p', 0, G_OPTION_ARG_STRING, &arg_preset, "The preset values to use for encoding", NULL }, - { "debug", 'x', 0, G_OPTION_ARG_NONE, &ghb_debug, "Spam a lot", NULL }, + { "device", 'd', 0, G_OPTION_ARG_FILENAME, &dvd_device, N_("The device or file to encode"), NULL }, + { "preset", 'p', 0, G_OPTION_ARG_STRING, &arg_preset, N_("The preset values to use for encoding"), NULL }, + { "debug", 'x', 0, G_OPTION_ARG_NONE, &ghb_debug, N_("Spam a lot"), NULL }, { NULL } }; @@ -857,7 +849,7 @@ main(int argc, char *argv[]) textdomain(GETTEXT_PACKAGE); #endif - context = g_option_context_new("- Transcode media formats"); + context = g_option_context_new(_("- Transcode media formats")); g_option_context_add_main_entries(context, entries, GETTEXT_PACKAGE); g_option_context_add_group(context, gtk_get_option_group(TRUE)); #if defined(_ENABLE_GST) diff --git a/gtk/src/makedeps.py b/gtk/src/makedeps.py index 9fecd37fe..79914ef5f 100644 --- a/gtk/src/makedeps.py +++ b/gtk/src/makedeps.py @@ -2,6 +2,7 @@ import collections import plistlib +import sys DepEntry = collections.namedtuple('DepEntry', 'widget dep enable die hide') dep_map = ( @@ -27,9 +28,6 @@ dep_map = ( DepEntry("VideoFramerate", "VideoFrameratePFR", "source", True, True), DepEntry("VideoFramerate", "VideoFramerateVFR", "source", False, True), DepEntry("VideoTwoPass", "VideoTurboTwoPass", "TRUE", False, False), - DepEntry("FileFormat", "Mp4LargeFile", "mp4", False, True), - DepEntry("FileFormat", "Mp4HttpOptimize", "mp4", False, True), - DepEntry("FileFormat", "Mp4iPodCompatible", "mp4", False, True), DepEntry("PictureDecombDeinterlace", "PictureDeinterlace", "TRUE", True, True), DepEntry("PictureDecombDeinterlace", "PictureDeinterlaceCustom", "TRUE", True, True), DepEntry("PictureDecombDeinterlace", "PictureDeinterlaceLabel", "TRUE", True, True), @@ -49,14 +47,8 @@ dep_map = ( DepEntry("VideoEncoder", "x264_tab", "x264", False, True), DepEntry("VideoEncoder", "x264VideoSettings", "x264", False, True), DepEntry("VideoEncoder", "lavc_mpeg4_tab", "ffmpeg|ffmpeg4|ffmpeg2", False, True), - DepEntry("VideoEncoder", "Mp4iPodCompatible", "x264", False, False), - DepEntry("AudioTrackQualityEnable", "AudioTrackQuality", "FALSE", True, False), - DepEntry("AudioTrackQualityEnable", "AudioTrackQualityValue", "FALSE", True, False), DepEntry("AudioTrackQualityEnable", "AudioBitrateLabel", "TRUE", True, False), DepEntry("AudioTrackQualityEnable", "AudioBitrate", "TRUE", True, False), - DepEntry("AudioEncoderActual", "AudioTrackQualityEnable", "lame|vorbis", False, True), - DepEntry("AudioEncoderActual", "AudioTrackQuality", "lame|vorbis", False, True), - DepEntry("AudioEncoderActual", "AudioTrackQualityValue", "lame|vorbis", False, True), DepEntry("AudioEncoderActual", "AudioBitrateLabel", "copy:mp3|copy:aac|copy:ac3|copy:dts|copy:dtshd", True, False), DepEntry("AudioEncoderActual", "AudioBitrate", "copy:mp3|copy:aac|copy:ac3|copy:dts|copy:dtshd", True, False), DepEntry("AudioEncoderActual", "AudioSamplerateLabel", "copy:mp3|copy:aac|copy:ac3|copy:dts|copy:dtshd", True, False), diff --git a/gtk/src/preview.c b/gtk/src/preview.c index 126943a54..561deb15a 100644 --- a/gtk/src/preview.c +++ b/gtk/src/preview.c @@ -14,6 +14,7 @@ #include <unistd.h> #include <glib.h> #include <glib/gstdio.h> +#include <glib/gi18n.h> #include <glib-object.h> #include "ghbcompat.h" @@ -558,8 +559,8 @@ live_preview_cb(GstBus *bus, GstMessage *msg, gpointer data) gchar *message, *desc; desc = gst_missing_plugin_message_get_description(msg); message = g_strdup_printf( - "Missing GStreamer plugin\n" - "Audio or Video may not play as expected\n\n%s", + _("Missing GStreamer plugin\n" + "Audio or Video may not play as expected\n\n%s"), desc); ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Ok", NULL); g_free(message); @@ -1286,16 +1287,16 @@ picture_settings_alt2_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud) window = GHB_WIDGET(ud->builder, "settings_window"); if (!active) { - gtk_button_set_label(GTK_BUTTON(toggle), "Hide Settings"); + gtk_button_set_label(GTK_BUTTON(toggle), _("Hide Settings")); gtk_widget_set_tooltip_text(toggle, - "Hide the picture settings window while " - "leaving the preview visible."); + _("Hide the picture settings window while " + "leaving the preview visible.")); gtk_widget_show(window); } else { - gtk_button_set_label(GTK_BUTTON(toggle), "Show Settings"); - gtk_widget_set_tooltip_text(toggle, "Show picture settings."); + gtk_button_set_label(GTK_BUTTON(toggle), _("Show Settings")); + gtk_widget_set_tooltip_text(toggle, _("Show picture settings.")); gtk_widget_hide(window); } } diff --git a/gtk/src/queuehandler.c b/gtk/src/queuehandler.c index d8d1e18a6..8642bfe21 100644 --- a/gtk/src/queuehandler.c +++ b/gtk/src/queuehandler.c @@ -13,6 +13,7 @@ #include "ghbcompat.h" #include <glib/gstdio.h> +#include <glib/gi18n.h> #include <gio/gio.h> #include "hb.h" #include "settings.h" @@ -93,13 +94,13 @@ add_to_queue_list(signal_user_data_t *ud, GValue *settings, GtkTreeIter *piter) vqtype = ghb_settings_get_boolean(settings, "vquality_type_constant"); if (!vqtype) pass2 = ghb_settings_get_boolean(settings, "VideoTwoPass"); - const gchar *points = "Chapters"; + const gchar *points = _("Chapters"); if (ghb_settings_combo_int(settings, "PtoPType") == 0) - points = "Chapters"; + points = _("Chapters"); else if (ghb_settings_combo_int(settings, "PtoPType") == 1) - points = "Seconds"; + points = _("Seconds"); else if (ghb_settings_combo_int(settings, "PtoPType") == 2) - points = "Frames"; + points = _("Frames"); info = g_strdup_printf ( "<big><b>%s</b></big> " @@ -172,7 +173,7 @@ add_to_queue_list(signal_user_data_t *ud, GValue *settings, GtkTreeIter *piter) g_string_append_printf(str, "<b>Format:</b> <small>%s Container</small>\n", container); } - if (mux == HB_MUX_MP4) + if (mux & HB_MUX_MASK_MP4) { gboolean ipod, http, large; @@ -549,11 +550,11 @@ validate_settings(signal_user_data_t *ud, GValue *settings, gint batch) if (strcmp(dest, filename) == 0) { message = g_strdup_printf( - "Destination: %s\n\n" + _("Destination: %s\n\n" "Another queued job has specified the same destination.\n" - "Do you want to overwrite?", + "Do you want to overwrite?"), dest); - if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "Cancel", "Overwrite")) + if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, _("Cancel"), _("Overwrite"))) { g_free(filename); g_free(dest); @@ -569,10 +570,10 @@ validate_settings(signal_user_data_t *ud, GValue *settings, gint batch) if (!g_file_test(destdir, G_FILE_TEST_IS_DIR)) { message = g_strdup_printf( - "Destination: %s\n\n" - "This is not a valid directory.", + _("Destination: %s\n\n" + "This is not a valid directory."), destdir); - ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL); + ghb_message_dialog(GTK_MESSAGE_ERROR, message, _("Cancel"), NULL); g_free(dest); g_free(message); g_free(destdir); @@ -583,10 +584,10 @@ validate_settings(signal_user_data_t *ud, GValue *settings, gint batch) if (g_access(destdir, R_OK|W_OK) != 0) { message = g_strdup_printf( - "Destination: %s\n\n" - "Can not read or write the directory.", + _("Destination: %s\n\n" + "Can not read or write the directory."), destdir); - ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL); + ghb_message_dialog(GTK_MESSAGE_ERROR, message, _("Cancel"), NULL); g_free(dest); g_free(message); g_free(destdir); @@ -614,10 +615,10 @@ validate_settings(signal_user_data_t *ud, GValue *settings, gint batch) if (size < fsize) { message = g_strdup_printf( - "Destination filesystem is almost full: %uM free\n\n" - "Encode may be incomplete if you proceed.\n", + _("Destination filesystem is almost full: %uM free\n\n" + "Encode may be incomplete if you proceed.\n"), (guint)(size / (1024L*1024L))); - if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "Cancel", "Proceed")) + if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, _("Cancel"), _("Proceed"))) { g_free(dest); g_free(message); @@ -635,11 +636,11 @@ validate_settings(signal_user_data_t *ud, GValue *settings, gint batch) if (g_file_test(dest, G_FILE_TEST_EXISTS)) { message = g_strdup_printf( - "Destination: %s\n\n" + _("Destination: %s\n\n" "File already exists.\n" - "Do you want to overwrite?", + "Do you want to overwrite?"), dest); - if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "Cancel", "Overwrite")) + if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, _("Cancel"), _("Overwrite"))) { g_free(dest); g_free(message); @@ -1028,60 +1029,60 @@ ghb_queue_buttons_grey(signal_user_data_t *ud) { gtk_widget_set_sensitive (widget, TRUE); gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(widget), "hb-stop"); - gtk_tool_button_set_label(GTK_TOOL_BUTTON(widget), "Stop"); - gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(widget), "Stop Encoding"); + gtk_tool_button_set_label(GTK_TOOL_BUTTON(widget), _("Stop")); + gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(widget), _("Stop Encoding")); } else { gtk_widget_set_sensitive (widget, show_start); gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(widget), "hb-start"); - gtk_tool_button_set_label(GTK_TOOL_BUTTON(widget), "Start"); - gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(widget), "Start Encoding"); + gtk_tool_button_set_label(GTK_TOOL_BUTTON(widget), _("Start")); + gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(widget), _("Start Encoding")); } widget = GHB_WIDGET (ud->builder, "queue_start2"); if (show_stop) { gtk_widget_set_sensitive (widget, TRUE); gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(widget), "hb-stop"); - gtk_tool_button_set_label(GTK_TOOL_BUTTON(widget), "Stop"); - gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(widget), "Stop Encoding"); + gtk_tool_button_set_label(GTK_TOOL_BUTTON(widget), _("Stop")); + gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(widget), _("Stop Encoding")); } else { gtk_widget_set_sensitive (widget, show_start); gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(widget), "hb-start"); - gtk_tool_button_set_label(GTK_TOOL_BUTTON(widget), "Start"); - gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(widget), "Start Encoding"); + gtk_tool_button_set_label(GTK_TOOL_BUTTON(widget), _("Start")); + gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(widget), _("Start Encoding")); } widget = GHB_WIDGET (ud->builder, "queue_pause1"); if (paused) { gtk_widget_set_sensitive (widget, show_stop); gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(widget), "hb-start"); - gtk_tool_button_set_label(GTK_TOOL_BUTTON(widget), "Resume"); - gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(widget), "Resume Encoding"); + gtk_tool_button_set_label(GTK_TOOL_BUTTON(widget), _("Resume")); + gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(widget), _("Resume Encoding")); } else { gtk_widget_set_sensitive (widget, show_stop); gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(widget), "hb-pause"); - gtk_tool_button_set_label(GTK_TOOL_BUTTON(widget), "Pause"); - gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(widget), "Pause Encoding"); + gtk_tool_button_set_label(GTK_TOOL_BUTTON(widget), _("Pause")); + gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(widget), _("Pause Encoding")); } widget = GHB_WIDGET (ud->builder, "queue_pause2"); if (paused) { gtk_widget_set_sensitive (widget, show_stop); gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(widget), "hb-start"); - gtk_tool_button_set_label(GTK_TOOL_BUTTON(widget), "Resume"); - gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(widget), "Resume Encoding"); + gtk_tool_button_set_label(GTK_TOOL_BUTTON(widget), _("Resume")); + gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(widget), _("Resume Encoding")); } else { gtk_widget_set_sensitive (widget, show_stop); gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(widget), "hb-pause"); - gtk_tool_button_set_label(GTK_TOOL_BUTTON(widget), "Pause"); - gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(widget), "Pause Encoding"); + gtk_tool_button_set_label(GTK_TOOL_BUTTON(widget), _("Pause")); + gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(widget), _("Pause Encoding")); } action = GHB_ACTION (ud->builder, "queue_start_menu"); @@ -1090,15 +1091,15 @@ ghb_queue_buttons_grey(signal_user_data_t *ud) gtk_action_set_sensitive (action, TRUE); #if GTK_CHECK_VERSION(2, 16, 0) gtk_action_set_icon_name(action, "hb-stop"); - gtk_action_set_label(action, "S_top Queue"); - gtk_action_set_tooltip(action, "Stop Encoding"); + gtk_action_set_label(action, _("S_top Queue")); + gtk_action_set_tooltip(action, _("Stop Encoding")); #else g_object_set_property(G_OBJECT(action), "icon-name", ghb_string_value("hb-stop")); g_object_set_property(G_OBJECT(action), "label", - ghb_string_value("S_top Queue")); + ghb_string_value(_("S_top Queue"))); g_object_set_property(G_OBJECT(action), "tooltip", - ghb_string_value("Stop Encoding")); + ghb_string_value(_("Stop Encoding"))); #endif } else @@ -1106,15 +1107,15 @@ ghb_queue_buttons_grey(signal_user_data_t *ud) gtk_action_set_sensitive (action, show_start); #if GTK_CHECK_VERSION(2, 16, 0) gtk_action_set_icon_name(action, "hb-start"); - gtk_action_set_label(action, "_Start Queue"); - gtk_action_set_tooltip(action, "Start Encoding"); + gtk_action_set_label(action, _("_Start Queue")); + gtk_action_set_tooltip(action, _("Start Encoding")); #else g_object_set_property(G_OBJECT(action), "icon-name", ghb_string_value("hb-start")); g_object_set_property(G_OBJECT(action), "label", - ghb_string_value("_Start Queue")); + ghb_string_value(_("_Start Queue"))); g_object_set_property(G_OBJECT(action), "tooltip", - ghb_string_value("Start Encoding")); + ghb_string_value(_("Start Encoding"))); #endif } action = GHB_ACTION (ud->builder, "queue_pause_menu"); @@ -1129,9 +1130,9 @@ ghb_queue_buttons_grey(signal_user_data_t *ud) g_object_set_property(G_OBJECT(action), "icon-name", ghb_string_value("hb-start")); g_object_set_property(G_OBJECT(action), "label", - ghb_string_value("_Resume Queue")); + ghb_string_value(_("_Resume Queue"))); g_object_set_property(G_OBJECT(action), "tooltip", - ghb_string_value("Resume Encoding")); + ghb_string_value(_("Resume Encoding"))); #endif } else @@ -1139,15 +1140,15 @@ ghb_queue_buttons_grey(signal_user_data_t *ud) gtk_action_set_sensitive (action, show_stop); #if GTK_CHECK_VERSION(2, 16, 0) gtk_action_set_icon_name(action, "hb-pause"); - gtk_action_set_label(action, "_Pause Queue"); - gtk_action_set_tooltip(action, "Pause Encoding"); + gtk_action_set_label(action, _("_Pause Queue")); + gtk_action_set_tooltip(action, _("Pause Encoding")); #else g_object_set_property(G_OBJECT(action), "icon-name", ghb_string_value("hb-pause")); g_object_set_property(G_OBJECT(action), "label", - ghb_string_value("_Pause Queue")); + ghb_string_value(_("_Pause Queue"))); g_object_set_property(G_OBJECT(action), "tooltip", - ghb_string_value("Pause Encoding")); + ghb_string_value(_("Pause Encoding"))); #endif } } @@ -1180,8 +1181,8 @@ queue_start_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud) if (state & (GHB_STATE_WORKING | GHB_STATE_SEARCHING | GHB_STATE_SCANNING | GHB_STATE_MUXING)) { - ghb_cancel_encode(ud, "You are currently encoding. " - "What would you like to do?"); + ghb_cancel_encode(ud, _("You are currently encoding. " + "What would you like to do?\n\n")); return; } @@ -1260,12 +1261,9 @@ find_pid: if (unfinished) { message = g_strdup_printf( - "You have %d unfinished job%s in a saved queue.\n\n" - "Would you like to reload %s?", - unfinished, - (unfinished > 1) ? "s" : "", - (unfinished > 1) ? "them" : "it"); - if (ghb_message_dialog(GTK_MESSAGE_QUESTION, message, "No", "Yes")) + _("You have %d unfinished job(s) in a saved queue.\n\n" + "Would you like to reload them?"), unfinished); + if (ghb_message_dialog(GTK_MESSAGE_QUESTION, message, _("No"), _("Yes"))) { GtkWidget *widget = GHB_WIDGET (ud->builder, "queue_window"); gtk_widget_show (widget); diff --git a/libhb/common.c b/libhb/common.c index 5766066ac..5ff333273 100644 --- a/libhb/common.c +++ b/libhb/common.c @@ -12,9 +12,12 @@ #include <ctype.h> #include <sys/time.h> -#include "common.h" -#include "lang.h" #include "hb.h" +#include "lang.h" +#include "common.h" +#ifdef USE_QSV +#include "qsv_common.h" +#endif /********************************************************************** * Global variables @@ -153,10 +156,10 @@ hb_mixdown_t *hb_audio_mixdowns_first_item = NULL; hb_mixdown_t *hb_audio_mixdowns_last_item = NULL; hb_mixdown_internal_t hb_audio_mixdowns[] = { - // legacy mixdowns (disabled) - { { "AC3 Passthru", "ac3pass", HB_AMIXDOWN_NONE, }, NULL, 0, }, - { { "DTS Passthru", "dtspass", HB_AMIXDOWN_NONE, }, NULL, 0, }, - { { "DTS-HD Passthru", "dtshdpass", HB_AMIXDOWN_NONE, }, NULL, 0, }, + // legacy mixdowns, back to HB 0.9.4 whenever possible (disabled) + { { "AC3 Passthru", "", HB_AMIXDOWN_NONE, }, NULL, 0, }, + { { "DTS Passthru", "", HB_AMIXDOWN_NONE, }, NULL, 0, }, + { { "DTS-HD Passthru", "", HB_AMIXDOWN_NONE, }, NULL, 0, }, { { "6-channel discrete", "6ch", HB_AMIXDOWN_5POINT1, }, NULL, 0, }, // actual mixdowns { { "None", "none", HB_AMIXDOWN_NONE, }, NULL, 1, }, @@ -184,27 +187,28 @@ hb_encoder_t *hb_video_encoders_first_item = NULL; hb_encoder_t *hb_video_encoders_last_item = NULL; hb_encoder_internal_t hb_video_encoders[] = { - // legacy encoders, all the way back to HB 0.7.1 (disabled) - { { "x264 (Main profile)", "", HB_VCODEC_X264, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_VCODEC_H264, }, - { { "x264 (Baseline profile)", "", HB_VCODEC_X264, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_VCODEC_H264, }, - { { "x264 (h.264 Main)", "", HB_VCODEC_X264, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_VCODEC_H264, }, - { { "x264 (h.264 iPod)", "", HB_VCODEC_X264, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_VCODEC_H264, }, - { { "", "x264b13", HB_VCODEC_X264, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_VCODEC_H264, }, - { { "", "x264b30", HB_VCODEC_X264, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_VCODEC_H264, }, - { { "XviD", "xvid", HB_VCODEC_FFMPEG_MPEG4, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_VCODEC_MPEG4, }, - { { "MPEG-4 (XviD)", "", HB_VCODEC_FFMPEG_MPEG4, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_VCODEC_MPEG4, }, - { { "FFmpeg", "ffmpeg", HB_VCODEC_FFMPEG_MPEG4, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_VCODEC_MPEG4, }, + // legacy encoders, back to HB 0.9.4 whenever possible (disabled) + { { "FFmpeg", "ffmpeg", HB_VCODEC_FFMPEG_MPEG4, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_VCODEC_MPEG4, }, + { { "MPEG-4 (FFmpeg)", "ffmpeg4", HB_VCODEC_FFMPEG_MPEG4, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_VCODEC_MPEG4, }, + { { "MPEG-2 (FFmpeg)", "ffmpeg2", HB_VCODEC_FFMPEG_MPEG2, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_VCODEC_MPEG2, }, + { { "VP3 (Theora)", "libtheora", HB_VCODEC_THEORA, HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_VCODEC_THEORA, }, // actual encoders - { { "H.264 (x264)", "x264", HB_VCODEC_X264, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_H264, }, - { { "MPEG-4 (FFmpeg)", "ffmpeg4", HB_VCODEC_FFMPEG_MPEG4, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_MPEG4, }, - { { "MPEG-2 (FFmpeg)", "ffmpeg2", HB_VCODEC_FFMPEG_MPEG2, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_MPEG2, }, - { { "VP3 (Theora)", "theora", HB_VCODEC_THEORA, HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_THEORA, }, + { { "H.264 (x264)", "x264", HB_VCODEC_X264, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_H264, }, + { { "H.264 (Intel QSV)", "qsv_h264", HB_VCODEC_QSV_H264, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_H264, }, + { { "MPEG-4", "mpeg4", HB_VCODEC_FFMPEG_MPEG4, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_MPEG4, }, + { { "MPEG-2", "mpeg2", HB_VCODEC_FFMPEG_MPEG2, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_MPEG2, }, + { { "Theora", "theora", HB_VCODEC_THEORA, HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_THEORA, }, }; int hb_video_encoders_count = sizeof(hb_video_encoders) / sizeof(hb_video_encoders[0]); static int hb_video_encoder_is_enabled(int encoder) { switch (encoder) { +#ifdef USE_QSV + case HB_VCODEC_QSV_H264: + return hb_qsv_available(); +#endif + // the following encoders are always enabled case HB_VCODEC_X264: case HB_VCODEC_THEORA: @@ -221,28 +225,31 @@ hb_encoder_t *hb_audio_encoders_first_item = NULL; hb_encoder_t *hb_audio_encoders_last_item = NULL; hb_encoder_internal_t hb_audio_encoders[] = { - // legacy encoders (disabled) - { { "AC3", "ac3", HB_ACODEC_AC3, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_ACODEC_AC3, }, - { { "AC3 (pass-thru)", "ac3pass", HB_ACODEC_AC3_PASS, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_ACODEC_AC3_PASS, }, - { { "DTS (pass-thru)", "dtspass", HB_ACODEC_DCA_PASS, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_ACODEC_DTS_PASS, }, + // legacy encoders, back to HB 0.9.4 whenever possible (disabled) { { "", "dts", HB_ACODEC_DCA_PASS, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_ACODEC_DTS_PASS, }, + { { "AAC (ffmpeg)", "ffaac", HB_ACODEC_FFAAC, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_ACODEC_AAC, }, + { { "AC3 (ffmpeg)", "ffac3", HB_ACODEC_AC3, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_ACODEC_AC3, }, + { { "MP3 (lame)", "lame", HB_ACODEC_LAME, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_ACODEC_MP3, }, + { { "Vorbis (vorbis)", "libvorbis", HB_ACODEC_VORBIS, HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_ACODEC_VORBIS, }, + { { "FLAC (ffmpeg)", "ffflac", HB_ACODEC_FFFLAC, HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_ACODEC_FLAC, }, + { { "FLAC (24-bit)", "ffflac24", HB_ACODEC_FFFLAC24, HB_MUX_MASK_MKV, }, NULL, 0, HB_GID_ACODEC_FLAC, }, // actual encoders { { "AAC (CoreAudio)", "ca_aac", HB_ACODEC_CA_AAC, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AAC, }, { { "HE-AAC (CoreAudio)", "ca_haac", HB_ACODEC_CA_HAAC, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AAC_HE, }, + { { "AAC (faac)", "faac", HB_ACODEC_FAAC, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AAC, }, + { { "AAC (avcodec)", "av_aac", HB_ACODEC_FFAAC, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AAC, }, { { "AAC (FDK)", "fdk_aac", HB_ACODEC_FDK_AAC, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AAC, }, { { "HE-AAC (FDK)", "fdk_haac", HB_ACODEC_FDK_HAAC, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AAC_HE, }, - { { "AAC (faac)", "faac", HB_ACODEC_FAAC, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AAC, }, - { { "AAC (ffmpeg)", "ffaac", HB_ACODEC_FFAAC, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AAC, }, { { "AAC Passthru", "copy:aac", HB_ACODEC_AAC_PASS, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AAC_PASS, }, - { { "AC3 (ffmpeg)", "ffac3", HB_ACODEC_AC3, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AC3, }, + { { "AC3", "ac3", HB_ACODEC_AC3, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AC3, }, { { "AC3 Passthru", "copy:ac3", HB_ACODEC_AC3_PASS, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AC3_PASS, }, { { "DTS Passthru", "copy:dts", HB_ACODEC_DCA_PASS, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_DTS_PASS, }, { { "DTS-HD Passthru", "copy:dtshd", HB_ACODEC_DCA_HD_PASS, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_DTSHD_PASS, }, - { { "MP3 (lame)", "lame", HB_ACODEC_LAME, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_MP3, }, + { { "MP3", "mp3", HB_ACODEC_LAME, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_MP3, }, { { "MP3 Passthru", "copy:mp3", HB_ACODEC_MP3_PASS, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_MP3_PASS, }, - { { "Vorbis (vorbis)", "vorbis", HB_ACODEC_VORBIS, HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_VORBIS, }, - { { "FLAC (ffmpeg)", "ffflac", HB_ACODEC_FFFLAC, HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_FLAC, }, - { { "FLAC (24-bit)", "ffflac24", HB_ACODEC_FFFLAC24, HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_FLAC, }, + { { "Vorbis", "vorbis", HB_ACODEC_VORBIS, HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_VORBIS, }, + { { "FLAC 16-bit", "flac16", HB_ACODEC_FFFLAC, HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_FLAC, }, + { { "FLAC 24-bit", "flac24", HB_ACODEC_FFFLAC24, HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_FLAC, }, { { "Auto Passthru", "copy", HB_ACODEC_AUTO_PASS, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_ACODEC_AUTO_PASS, }, }; int hb_audio_encoders_count = sizeof(hb_audio_encoders) / sizeof(hb_audio_encoders[0]); @@ -261,12 +268,12 @@ static int hb_audio_encoder_is_enabled(int encoder) return 1; #endif -#if 1 //#ifdef USE_FAAC +#ifdef USE_FAAC case HB_ACODEC_FAAC: return 1; #endif -#if 1 //#ifdef USE_LIBAV_AAC +#ifdef USE_LIBAV_AAC case HB_ACODEC_FFAAC: return 1; #endif @@ -301,28 +308,31 @@ hb_container_t *hb_containers_first_item = NULL; hb_container_t *hb_containers_last_item = NULL; hb_container_internal_t hb_containers[] = { - // legacy muxers (disabled) - { { "AVI file", "avi", "avi", 0, }, NULL, 0, HB_GID_MUX_MP4, }, - { { "M4V file", "m4v", "m4v", 0, }, NULL, 0, HB_GID_MUX_MP4, }, - { { "MP4 file", "mp4", "mp4", 0, }, NULL, 0, HB_GID_MUX_MP4, }, - { { "OGM file", "ogm", "ogm", 0, }, NULL, 0, HB_GID_MUX_MKV, }, - { { "MKV file", "mkv", "mkv", 0, }, NULL, 0, HB_GID_MUX_MKV, }, + // legacy muxers, back to HB 0.9.4 whenever possible (disabled) + { { "M4V file", "m4v", "m4v", 0, }, NULL, 0, HB_GID_MUX_MP4, }, + { { "MP4 file", "mp4", "mp4", 0, }, NULL, 0, HB_GID_MUX_MP4, }, + { { "MKV file", "mkv", "mkv", 0, }, NULL, 0, HB_GID_MUX_MKV, }, // actual muxers - { { "MPEG-4 (mp4v2)", "mp4v2", "mp4", HB_MUX_MP4V2, }, NULL, 1, HB_GID_MUX_MP4, }, - { { "Matroska (libmkv)", "libmkv", "mkv", HB_MUX_LIBMKV, }, NULL, 1, HB_GID_MUX_MKV, }, + { { "MPEG-4 (mp4v2)", "mp4v2", "mp4", HB_MUX_MP4V2, }, NULL, 1, HB_GID_MUX_MP4, }, + { { "Matroska (libmkv)", "libmkv", "mkv", HB_MUX_LIBMKV, }, NULL, 1, HB_GID_MUX_MKV, }, + { { "MPEG-4 (avformat)", "av_mp4", "mp4", HB_MUX_AV_MP4, }, NULL, 1, HB_GID_MUX_MP4, }, + { { "Matroska (avformat)", "av_mkv", "mkv", HB_MUX_AV_MKV, }, NULL, 1, HB_GID_MUX_MKV, }, }; int hb_containers_count = sizeof(hb_containers) / sizeof(hb_containers[0]); static int hb_container_is_enabled(int format) { switch (format) { -#if 1 //#ifdef USE_MP4V2 +#ifdef USE_MP4V2 case HB_MUX_MP4V2: - return 1; #endif - - // the following muxers are always enabled +#ifdef USE_LIBMKV case HB_MUX_LIBMKV: +#endif +#ifdef USE_AVFORMAT + case HB_MUX_AV_MP4: + case HB_MUX_AV_MKV: +#endif return 1; default: @@ -1086,6 +1096,55 @@ const hb_rate_t* hb_audio_bitrate_get_next(const hb_rate_t *last) // // direction says whether 'low' limit is highest or lowest // quality (direction 0 == lowest value is worst quality) +void hb_video_quality_get_limits(uint32_t codec, float *low, float *high, + float *granularity, int *direction) +{ + switch (codec) + { + case HB_VCODEC_X264: + *direction = 1; + *granularity = 0.1; + *low = 0.; + *high = 51.; + break; + + case HB_VCODEC_THEORA: + *direction = 0; + *granularity = 1.; + *low = 0.; + *high = 63.; + break; + + case HB_VCODEC_FFMPEG_MPEG2: + case HB_VCODEC_FFMPEG_MPEG4: + default: + *direction = 1; + *granularity = 1.; + *low = 1.; + *high = 31.; + break; + } +} + +const char* hb_video_quality_get_name(uint32_t codec) +{ + switch (codec) + { + case HB_VCODEC_X264: + return "RF"; + + default: + return "QP"; + } +} + +// Get limits and hints for the UIs. +// +// granularity sets the minimum step increments that should be used +// (it's ok to round up to some nice multiple if you like) +// +// direction says whether 'low' limit is highest or lowest +// quality (direction 0 == lowest value is worst quality) void hb_audio_quality_get_limits(uint32_t codec, float *low, float *high, float *granularity, int *direction) { @@ -1314,7 +1373,6 @@ int hb_mixdown_has_codec_support(int mixdown, uint32_t codec) return (mixdown <= HB_AMIXDOWN_7POINT1); case HB_ACODEC_LAME: - case HB_ACODEC_FFAAC: return (mixdown <= HB_AMIXDOWN_DOLBYPLII); case HB_ACODEC_FAAC: @@ -2826,6 +2884,12 @@ static void job_setup( hb_job_t * job, hb_title_t * title ) job->list_attachment = hb_attachment_list_copy( title->list_attachment ); job->metadata = hb_metadata_copy( title->metadata ); + +#ifdef USE_QSV + job->qsv_enc_info.is_init_done = 0; + job->qsv_decode = title->qsv_decode_support; + job->qsv_async_depth = AV_QSV_ASYNC_DEPTH_DEFAULT; +#endif } static void job_clean( hb_job_t * job ) @@ -3085,6 +3149,20 @@ hb_filter_object_t * hb_filter_init( int filter_id ) filter = &hb_filter_rotate; break; +#ifdef USE_QSV + case HB_FILTER_QSV: + filter = &hb_filter_qsv; + break; + + case HB_FILTER_QSV_PRE: + filter = &hb_filter_qsv_pre; + break; + + case HB_FILTER_QSV_POST: + filter = &hb_filter_qsv_post; + break; +#endif + default: filter = NULL; break; @@ -3505,46 +3583,50 @@ int hb_subtitle_can_burn( int source ) int hb_subtitle_can_pass( int source, int mux ) { - if ( mux == HB_MUX_MKV ) + switch (mux) { - switch( source ) - { - case PGSSUB: - case VOBSUB: - case SSASUB: - case SRTSUB: - case UTF8SUB: - case TX3GSUB: - case CC608SUB: - case CC708SUB: - return 1; + case HB_MUX_AV_MKV: + case HB_MUX_LIBMKV: + switch( source ) + { + case PGSSUB: + case VOBSUB: + case SSASUB: + case SRTSUB: + case UTF8SUB: + case TX3GSUB: + case CC608SUB: + case CC708SUB: + return 1; - default: - return 0; - } - } - else if ( mux == HB_MUX_MP4 ) - { - switch( source ) - { - case VOBSUB: - case SSASUB: - case SRTSUB: - case UTF8SUB: - case TX3GSUB: - case CC608SUB: - case CC708SUB: + default: + return 0; + } break; + + case HB_MUX_MP4V2: + if (source == VOBSUB) + { return 1; + } // fall through to next case... + case HB_MUX_AV_MP4: + switch( source ) + { + case SSASUB: + case SRTSUB: + case UTF8SUB: + case TX3GSUB: + case CC608SUB: + case CC708SUB: + return 1; - default: - return 0; - } - } - else - { - // Internal error. Should never get here. - hb_error("internel error. Bad mux %d\n", mux); - return 0; + default: + return 0; + } break; + + default: + // Internal error. Should never get here. + hb_error("internel error. Bad mux %d\n", mux); + return 0; } } diff --git a/libhb/common.h b/libhb/common.h index 7e5512514..28ed5f82a 100644 --- a/libhb/common.h +++ b/libhb/common.h @@ -111,6 +111,15 @@ typedef struct hb_lock_s hb_lock_t; #include "audio_remap.h" #include "libavutil/channel_layout.h" +#ifdef USE_QSV + +#ifndef DEBUG_ASSERT +#define DEBUG_ASSERT(x,y) { if ((x)) { hb_error("ASSERT: %s", y); exit(1); } } +#endif + +#include "libavcodec/qsv.h" +#endif + hb_list_t * hb_list_init(); int hb_list_count( const hb_list_t * ); void hb_list_add( hb_list_t *, void * ); @@ -271,6 +280,9 @@ int hb_audio_bitrate_get_default(uint32_t codec, int samplerate, in void hb_audio_bitrate_get_limits(uint32_t codec, int samplerate, int mixdown, int *low, int *high); const hb_rate_t* hb_audio_bitrate_get_next(const hb_rate_t *last); +void hb_video_quality_get_limits(uint32_t codec, float *low, float *high, float *granularity, int *direction); +const char* hb_video_quality_get_name(uint32_t codec); + void hb_audio_quality_get_limits(uint32_t codec, float *low, float *high, float *granularity, int *direction); float hb_audio_quality_get_best(uint32_t codec, float quality); float hb_audio_quality_get_default(uint32_t codec); @@ -409,12 +421,15 @@ struct hb_job_s pass: 0, 1 or 2 (or -1 for scan) advanced_opts: string of extra advanced encoder options areBframes: boolean to note if b-frames are included in advanced_opts */ -#define HB_VCODEC_MASK 0x00000FF +#define HB_VCODEC_MASK 0x0000FFF #define HB_VCODEC_X264 0x0000001 #define HB_VCODEC_THEORA 0x0000002 #define HB_VCODEC_FFMPEG_MPEG4 0x0000010 #define HB_VCODEC_FFMPEG_MPEG2 0x0000020 #define HB_VCODEC_FFMPEG_MASK 0x00000F0 +#define HB_VCODEC_QSV_H264 0x0000100 +#define HB_VCODEC_QSV_MASK 0x0000F00 +#define HB_VCODEC_H264_MASK (HB_VCODEC_X264|HB_VCODEC_QSV_H264) int vcodec; float vquality; @@ -472,9 +487,12 @@ struct hb_job_s */ #define HB_MUX_MASK 0xFF0000 #define HB_MUX_MP4V2 0x010000 -#define HB_MUX_MASK_MP4 0x0F0000 +#define HB_MUX_AV_MP4 0x020000 +#define HB_MUX_MASK_MP4 0x030000 #define HB_MUX_LIBMKV 0x100000 -#define HB_MUX_MASK_MKV 0xF00000 +#define HB_MUX_AV_MKV 0x200000 +#define HB_MUX_MASK_MKV 0x300000 +#define HB_MUX_MASK_AV 0x220000 /* default muxer for each container */ #define HB_MUX_MP4 HB_MUX_MP4V2 #define HB_MUX_MKV HB_MUX_LIBMKV @@ -507,6 +525,21 @@ struct hb_job_s int use_hwd; int use_decomb; int use_detelecine; +#ifdef USE_QSV + av_qsv_context *qsv; + int qsv_decode; + int qsv_async_depth; + // shared encoding parameters + // initialized by the QSV encoder, then used upstream (e.g. by filters) to + // configure their output so that it corresponds to what the encoder expects + struct + { + int pic_struct; + int align_width; + int align_height; + int is_init_done; + } qsv_enc_info; +#endif #ifdef __LIBHB__ /* Internal data */ @@ -603,6 +636,7 @@ struct hb_audio_config_s int normalize_mix_level; /* mix level normalization (boolean) */ int dither_method; /* dither algorithm */ char * name; /* Output track name */ + int delay; } out; /* Input */ @@ -839,6 +873,10 @@ struct hb_title_s char *container_name; int data_rate; +#ifdef USE_QSV + int qsv_decode_support; +#endif + hb_metadata_t *metadata; hb_list_t * list_chapter; @@ -937,6 +975,9 @@ typedef struct hb_work_info_s int color_prim; int color_transfer; int color_matrix; +#ifdef USE_QSV + int qsv_decode_support; +#endif }; struct { // info only valid for audio decoders @@ -1006,6 +1047,7 @@ extern hb_work_object_t hb_dectx3gsub; extern hb_work_object_t hb_decssasub; extern hb_work_object_t hb_decpgssub; extern hb_work_object_t hb_encavcodec; +extern hb_work_object_t hb_encqsv; extern hb_work_object_t hb_encx264; extern hb_work_object_t hb_enctheora; extern hb_work_object_t hb_deca52; @@ -1134,8 +1176,11 @@ struct hb_filter_object_s enum { + // for QSV - important to have before other filters + HB_FILTER_QSV_PRE = 1, + // First, filters that may change the framerate (drop or dup frames) - HB_FILTER_DETELECINE = 1, + HB_FILTER_DETELECINE, HB_FILTER_DECOMB, HB_FILTER_DEINTERLACE, HB_FILTER_VFR, @@ -1148,6 +1193,11 @@ enum // Finally filters that don't care what order they are in, // except that they must be after the above filters HB_FILTER_ROTATE, + + // for QSV - important to have as a last one + HB_FILTER_QSV_POST, + // default MSDK VPP filter + HB_FILTER_QSV, }; hb_filter_object_t * hb_filter_init( int filter_id ); diff --git a/libhb/decavcodec.c b/libhb/decavcodec.c index 461f87b66..95a95fbf1 100644 --- a/libhb/decavcodec.c +++ b/libhb/decavcodec.c @@ -46,6 +46,11 @@ #include "vadxva2.h" #endif +#ifdef USE_QSV +#include "enc_qsv.h" +#include "qsv_common.h" +#endif + static void compute_frame_duration( hb_work_private_t *pv ); static void flushDelayQueue( hb_work_private_t *pv ); static int decavcodecaInit( hb_work_object_t *, hb_job_t * ); @@ -109,8 +114,69 @@ struct hb_work_private_s hb_oclscale_t *opencl_scale; #endif hb_audio_resample_t *resample; +#ifdef USE_QSV + av_qsv_config qsv_config; + int qsv_decode; + const char *qsv_codec_name; +#define USE_QSV_PTS_WORKAROUND // work around out-of-order output timestamps +#ifdef USE_QSV_PTS_WORKAROUND + hb_list_t *qsv_pts_list; +#endif +#endif }; +#ifdef USE_QSV_PTS_WORKAROUND +// save/restore PTS if the decoder may not attach the right PTS to the frame +static void hb_av_add_new_pts(hb_list_t *list, int64_t new_pts) +{ + int index = 0; + int64_t *cur_item, *new_item; + if (list != NULL && new_pts != AV_NOPTS_VALUE) + { + new_item = malloc(sizeof(int64_t)); + if (new_item != NULL) + { + *new_item = new_pts; + // sort chronologically + for (index = 0; index < hb_list_count(list); index++) + { + cur_item = hb_list_item(list, index); + if (cur_item != NULL) + { + if (*cur_item == *new_item) + { + // no duplicates + free(new_item); + return; + } + if (*cur_item > *new_item) + { + // insert here + break; + } + } + } + hb_list_insert(list, index, new_item); + } + } +} +static int64_t hb_av_pop_next_pts(hb_list_t *list) +{ + int64_t *item, next_pts = AV_NOPTS_VALUE; + if (list != NULL && hb_list_count(list) > 0) + { + item = hb_list_item(list, 0); + if (item != NULL) + { + next_pts = *item; + hb_list_rem(list, item); + free(item); + } + } + return next_pts; +} +#endif + static void decodeAudio( hb_audio_t * audio, hb_work_private_t *pv, uint8_t *data, int size, int64_t pts ); static hb_buffer_t *link_buf_list( hb_work_private_t *pv ); @@ -293,7 +359,12 @@ static void closePrivData( hb_work_private_t ** ppv ) } if ( pv->context && pv->context->codec ) { - hb_avcodec_close( pv->context ); +#ifdef USE_QSV + if (!pv->qsv_decode) +#endif + { + hb_avcodec_close(pv->context); + } } if ( pv->context ) { @@ -305,11 +376,13 @@ static void closePrivData( hb_work_private_t ** ppv ) hb_list_empty( &pv->list ); } hb_audio_resample_free(pv->resample); + #ifdef USE_HWD if ( pv->opencl_scale ) { free( pv->opencl_scale ); } + if ( pv->dxva2 ) { #ifdef USE_OPENCL @@ -318,6 +391,21 @@ static void closePrivData( hb_work_private_t ** ppv ) hb_va_close( pv->dxva2 ); } #endif + +#ifdef USE_QSV_PTS_WORKAROUND + if (pv->qsv_decode && pv->qsv_pts_list != NULL) + + { + while (hb_list_count(pv->qsv_pts_list) > 0) + { + int64_t *item = hb_list_item(pv->qsv_pts_list, 0); + hb_list_rem(pv->qsv_pts_list, item); + free(item); + } + hb_list_close(&pv->qsv_pts_list); + } +#endif + free( pv ); } *ppv = NULL; @@ -615,6 +703,7 @@ static hb_buffer_t *copy_frame( hb_work_private_t *pv, AVFrame *frame ) w = pv->job->title->width; h = pv->job->title->height; } + #ifdef USE_HWD if (pv->dxva2 && pv->job) { @@ -651,6 +740,17 @@ static hb_buffer_t *copy_frame( hb_work_private_t *pv, AVFrame *frame ) #endif { hb_buffer_t *buf = hb_video_buffer_init( w, h ); + +#ifdef USE_QSV + // no need to copy the frame data when decoding with QSV to opaque memory + if (pv->qsv_decode && + pv->qsv_config.io_pattern == MFX_IOPATTERN_OUT_OPAQUE_MEMORY) + { + buf->qsv_details.qsv_atom = frame->data[2]; + return buf; + } +#endif + uint8_t *dst = buf->data; if (context->pix_fmt != AV_PIX_FMT_YUV420P || w != context->width || @@ -891,10 +991,42 @@ static int decodeFrame( hb_work_object_t *w, uint8_t *data, int size, int sequen avp.flags |= AV_PKT_FLAG_KEY; } +#ifdef USE_QSV_PTS_WORKAROUND + /* + * The MediaSDK decoder will return decoded frames in the correct order, + * but *sometimes* with the incorrect timestamp assigned to them. + * + * We work around it by saving the input timestamps (in chronological order) + * and restoring them after decoding. + */ + if (pv->qsv_decode && avp.data != NULL) + { + hb_av_add_new_pts(pv->qsv_pts_list, avp.pts); + } +#endif + if ( avcodec_decode_video2( pv->context, &frame, &got_picture, &avp ) < 0 ) { ++pv->decode_errors; } + +#ifdef USE_QSV + if (pv->qsv_decode && pv->job->qsv == NULL && pv->video_codec_opened > 0) + { + // this is quite late, but we can't be certain that the QSV context is + // available until after we call avcodec_decode_video2() at least once + pv->job->qsv = pv->context->priv_data; + } +#endif + +#ifdef USE_QSV_PTS_WORKAROUND + if (pv->qsv_decode && got_picture) + { + // we got a decoded frame, restore the lowest available PTS + frame.pkt_pts = hb_av_pop_next_pts(pv->qsv_pts_list); + } +#endif + if ( global_verbosity_level <= 1 ) { av_log_set_level( oldlevel ); @@ -1106,12 +1238,23 @@ static void decodeVideo( hb_work_object_t *w, uint8_t *data, int size, int seque } while ( pos < size ); /* the stuff above flushed the parser, now flush the decoder */ - if ( size <= 0 ) + if (size <= 0) { - while ( decodeFrame( w, NULL, 0, sequence, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0 ) ) + while (decodeFrame(w, NULL, 0, sequence, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0)) { + continue; } - flushDelayQueue( pv ); +#ifdef USE_QSV + if (pv->qsv_decode) + { + // flush a second time + while (decodeFrame(w, NULL, 0, sequence, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0)) + { + continue; + } + } +#endif + flushDelayQueue(pv); } } @@ -1153,14 +1296,52 @@ static int decavcodecvInit( hb_work_object_t * w, hb_job_t * job ) pv->title = w->title; pv->list = hb_list_init(); +#ifdef USE_QSV + if (hb_qsv_decode_is_enabled(job)) + { + // setup the QSV configuration + pv->qsv_config.io_pattern = MFX_IOPATTERN_OUT_OPAQUE_MEMORY; + pv->qsv_config.impl_requested = hb_qsv_impl_get_preferred(); + pv->qsv_config.async_depth = job->qsv_async_depth; + pv->qsv_config.sync_need = 0; + pv->qsv_config.usage_threaded = 1; + pv->qsv_config.additional_buffers = 64; // FIFO_LARGE + if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_LOOKAHEAD) + { + // more surfaces may be needed for the lookahead + pv->qsv_config.additional_buffers = 160; + } + pv->qsv_codec_name = hb_qsv_decode_get_codec_name(w->codec_param); + pv->qsv_decode = 1; + } + else + { + pv->qsv_decode = 0; + } +#endif + if( pv->job && pv->job->title && !pv->job->title->has_resolution_change ) { pv->threads = HB_FFMPEG_THREADS_AUTO; } + if ( pv->title->opaque_priv ) { AVFormatContext *ic = (AVFormatContext*)pv->title->opaque_priv; - AVCodec *codec = avcodec_find_decoder( w->codec_param ); + + AVCodec *codec = NULL; + +#ifdef USE_QSV + if (pv->qsv_decode) + { + codec = avcodec_find_decoder_by_name(pv->qsv_codec_name); + } + else +#endif + { + codec = avcodec_find_decoder(w->codec_param); + } + if ( codec == NULL ) { hb_log( "decavcodecvInit: failed to find codec for id (%d)", w->codec_param ); @@ -1186,10 +1367,22 @@ static int decavcodecvInit( hb_work_object_t * w, hb_job_t * job ) pv->opencl_scale = ( hb_oclscale_t * )malloc( sizeof( hb_oclscale_t ) ); memset( pv->opencl_scale, 0, sizeof( hb_oclscale_t ) ); pv->threads = 1; - } } #endif + + +#ifdef USE_QSV + if (pv->qsv_decode) + { +#ifdef USE_QSV_PTS_WORKAROUND + pv->qsv_pts_list = hb_list_init(); +#endif + // set the QSV configuration before opening the decoder + pv->context->hwaccel_context = &pv->qsv_config; + } +#endif + if ( hb_avcodec_open( pv->context, codec, NULL, pv->threads ) ) { hb_log( "decavcodecvInit: avcodec_open failed" ); @@ -1206,7 +1399,20 @@ static int decavcodecvInit( hb_work_object_t * w, hb_job_t * job ) } else { - AVCodec *codec = avcodec_find_decoder( w->codec_param ); + AVCodec *codec = NULL; + +#ifdef USE_QSV + if (pv->qsv_decode) + { + codec = avcodec_find_decoder_by_name(pv->qsv_codec_name); + } + else +#endif + { + codec = avcodec_find_decoder(w->codec_param); + } + + pv->parser = av_parser_init( w->codec_param ); pv->context = avcodec_alloc_context3( codec ); pv->context->workaround_bugs = FF_BUG_AUTODETECT; @@ -1333,7 +1539,19 @@ static int decavcodecvWork( hb_work_object_t * w, hb_buffer_t ** buf_in, // first frame because of M$ VC1 braindamage). if ( !pv->video_codec_opened ) { - AVCodec *codec = avcodec_find_decoder( w->codec_param ); + + AVCodec *codec = NULL; +#ifdef USE_QSV + if (pv->qsv_decode) + { + codec = avcodec_find_decoder_by_name(pv->qsv_codec_name); + } + else +#endif + { + codec = avcodec_find_decoder(w->codec_param); + } + if ( codec == NULL ) { hb_log( "decavcodecvWork: failed to find codec for id (%d)", w->codec_param ); @@ -1357,6 +1575,18 @@ static int decavcodecvWork( hb_work_object_t * w, hb_buffer_t ** buf_in, hb_buffer_close( &in ); return HB_WORK_OK; } + +#ifdef USE_QSV + if (pv->qsv_decode) + { +#ifdef USE_QSV_PTS_WORKAROUND + pv->qsv_pts_list = hb_list_init(); +#endif + // set the QSV configuration before opening the decoder + pv->context->hwaccel_context = &pv->qsv_config; + } +#endif + // disable threaded decoding for scan, can cause crashes if ( hb_avcodec_open( pv->context, codec, NULL, pv->threads ) ) { @@ -1580,6 +1810,11 @@ static int decavcodecvInfo( hb_work_object_t *w, hb_work_info_t *info ) } } +#ifdef USE_QSV + info->qsv_decode_support = hb_qsv_decode_is_supported(pv->context->codec_id, + pv->context->pix_fmt); +#endif + return 1; } diff --git a/libhb/deccc608sub.c b/libhb/deccc608sub.c index 1d16410e4..c18fa76b8 100644 --- a/libhb/deccc608sub.c +++ b/libhb/deccc608sub.c @@ -1497,6 +1497,7 @@ void write_cc_line_as_transcript (struct eia608_screen *data, struct s_write *wb * Put this subtitle in a hb_buffer_t and shove it into the subtitle fifo */ buffer = hb_buffer_init( length + 1 ); + buffer->s.frametype = HB_FRAME_SUBTITLE; buffer->s.start = wb->data608->current_visible_start_ms; buffer->s.stop = get_fts(wb); memcpy( buffer->data, wb->subline, length + 1 ); @@ -1650,6 +1651,7 @@ int write_cc_buffer_as_srt (struct eia608_screen *data, struct s_write *wb) if (wb->enc_buffer_used) { hb_buffer_t *buffer = hb_buffer_init( wb->enc_buffer_used + 1 ); + buffer->s.frametype = HB_FRAME_SUBTITLE; buffer->s.start = ms_start; buffer->s.stop = ms_end; memcpy( buffer->data, wb->enc_buffer, wb->enc_buffer_used + 1 ); diff --git a/libhb/decmetadata.c b/libhb/decmetadata.c index 5f6b6af7b..c7c0d9858 100644 --- a/libhb/decmetadata.c +++ b/libhb/decmetadata.c @@ -7,10 +7,12 @@ For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html */ -#include <mp4v2/mp4v2.h> #include "common.h" +#if defined(USE_MP4V2) +#include <mp4v2/mp4v2.h> + static int decmp4metadata( hb_title_t *title ) { MP4FileHandle input_file; @@ -172,6 +174,7 @@ static int decmp4metadata( hb_title_t *title ) } return result; } +#endif // USE_MP4V2 /* * decmetadata() @@ -190,6 +193,7 @@ int decmetadata( hb_title_t *title ) return 0; } +#if defined(USE_MP4V2) /* * Hacky way of figuring out if this is an MP4, in which case read the data using libmp4v2 */ @@ -197,5 +201,6 @@ int decmetadata( hb_title_t *title ) { return decmp4metadata( title ); } +#endif return 0; } diff --git a/libhb/decmpeg2.c b/libhb/decmpeg2.c index 8844a09af..2a186295d 100644 --- a/libhb/decmpeg2.c +++ b/libhb/decmpeg2.c @@ -911,6 +911,10 @@ static int decmpeg2Info( hb_work_object_t *w, hb_work_info_t *info ) info->level = m->info->sequence->profile_level_id & 0xf; info->name = "mpeg2"; +#ifdef USE_QSV + info->qsv_decode_support = 0; +#endif + if( pv->libmpeg2->info->sequence->flags & SEQ_FLAG_COLOUR_DESCRIPTION ) { switch( pv->libmpeg2->info->sequence->colour_primaries ) diff --git a/libhb/decomb.c b/libhb/decomb.c index 4c58858ba..462e11835 100644 --- a/libhb/decomb.c +++ b/libhb/decomb.c @@ -33,7 +33,6 @@ Original "Faster" settings: #define MODE_BLEND 2 // Use blending interpolation #define MODE_CUBIC 4 // Use cubic interpolation #define MODE_EEDI2 8 // Use EEDI2 interpolation -#define MODE_MCDEINT 16 // Post-process with mcdeint #define MODE_MASK 32 // Output combing masks instead of pictures #define MODE_BOB 64 // Deinterlace each field to a separate frame @@ -60,36 +59,21 @@ which will feed EEDI2 interpolations to yadif. 9: EEDI2->yadif 10: Switch between EEDI2 and blend 11: Switch between EEDI2->yadif and blend -17: Yadif->mcdeint -18: Blend->mcdeint -19: Switch between blending and yadif -> mcdeint -20: Cubic->mdeint -21: Cubic->yadif->mcdeint -22: Cubic or blend -> mcdeint -23: Cubic->yadif or blend -> mcdeint -24: EEDI2->mcdeint -25: EEDI2->yadif->mcdeint ...okay I'm getting bored now listing all these different modes 32: Passes through the combing mask for every combed frame (white for combed pixels, otherwise black) 33+: Overlay the combing mask for every combed frame on top of the filtered output (white for combed pixels) 12-15: EEDI2 will override cubic interpolation -16: DOES NOT WORK BY ITSELF-- mcdeint needs to be fed by another deinterlacer *****/ #include "hb.h" #include "hbffmpeg.h" #include "mpeg2dec/mpeg2.h" #include "eedi2.h" -#include "mcdeint.h" #include "taskset.h" #define PARITY_DEFAULT -1 -#define MCDEINT_MODE_DEFAULT -1 -#define MCDEINT_MODE_ENABLED 2 -#define MCDEINT_QP_DEFAULT 1 - #define ABS(a) ((a) > 0 ? (a) : (-(a))) #define MIN3(a,b,c) MIN(MIN(a,b),c) #define MAX3(a,b,c) MAX(MAX(a,b),c) @@ -169,9 +153,6 @@ struct hb_filter_private_s int yadif_ready; - int mcdeint_mode; - mcdeint_private_t mcdeint; - int deinterlaced_frames; int blended_frames; int unfiltered_frames; @@ -1981,8 +1962,6 @@ static void yadif_filter( hb_filter_private_t * pv, else { /* Just passing through... */ - - /* For mcdeint's benefit... */ pv->yadif_arguments[0].is_combed = is_combed; // 0 hb_buffer_copy(dst, pv->ref[1]); } @@ -2025,9 +2004,6 @@ static int hb_decomb_init( hb_filter_object_t * filter, pv->parity = PARITY_DEFAULT; - pv->mcdeint_mode = MCDEINT_MODE_DEFAULT; - int mcdeint_qp = MCDEINT_QP_DEFAULT; - if( filter->settings ) { sscanf( filter->settings, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", @@ -2058,11 +2034,6 @@ static int hb_decomb_init( hb_filter_object_t * filter, pv->segment_height[1] = hb_image_height(init->pix_fmt, pv->segment_height[0], 1); pv->segment_height[2] = hb_image_height(init->pix_fmt, pv->segment_height[0], 2); - if( pv->mode & MODE_MCDEINT ) - { - pv->mcdeint_mode = MCDEINT_MODE_ENABLED; - } - /* Allocate buffers to store comb masks. */ pv->mask = hb_frame_buffer_init(init->pix_fmt, init->width, init->height); pv->mask_filtered = hb_frame_buffer_init(init->pix_fmt, init->width, init->height); @@ -2487,9 +2458,6 @@ static int hb_decomb_init( hb_filter_object_t * filter, } } - mcdeint_init( &pv->mcdeint, pv->mcdeint_mode, mcdeint_qp, - init->pix_fmt, init->width, init->height ); - return 0; } @@ -2572,9 +2540,6 @@ static void hb_decomb_close( hb_filter_object_t * filter ) */ free( pv->yadif_arguments ); - /* Cleanup mcdeint specific buffers */ - mcdeint_close( &pv->mcdeint ); - free( pv ); filter->private_data = NULL; } @@ -2623,9 +2588,9 @@ static int hb_decomb_work( hb_filter_object_t * filter, tff = (pv->parity & 1) ^ 1; } - /* deinterlace both fields if mcdeint is enabled without bob */ + /* deinterlace both fields if bob */ int frame, num_frames = 1; - if (pv->mode & (MODE_MCDEINT | MODE_BOB)) + if (pv->mode & MODE_BOB) { num_frames = 2; } @@ -2660,24 +2625,9 @@ static int hb_decomb_work( hb_filter_object_t * filter, yadif_filter(pv, o_buf[idx], parity, tff); - // Unfortunately, all frames must be fed to mcdeint combed or - // not since it maintains state that is updated by each frame. - if (pv->mcdeint_mode >= 0) - { - if (o_buf[idx^1] == NULL) - { - o_buf[idx^1] = hb_video_buffer_init(in->f.width, in->f.height); - } - /* Perform mcdeint filtering */ - mcdeint_filter(o_buf[idx^1], o_buf[idx], parity, &pv->mcdeint); - - // If frame was combed, we will use results from mcdeint - // else we will use yadif result - if (pv->is_combed) - idx ^= 1; - } - - // Add to list of output buffers (should be at most 2) + // If bob, add all frames to output + // else, if not combed, add frame to output + // else if final iteration, add frame to output if ((pv->mode & MODE_BOB) || pv->is_combed == 0 || frame == num_frames - 1) diff --git a/libhb/decpgssub.c b/libhb/decpgssub.c index 8229c6eda..f6004cb6d 100644 --- a/libhb/decpgssub.c +++ b/libhb/decpgssub.c @@ -282,12 +282,31 @@ static int decsubWork( hb_work_object_t * w, hb_buffer_t ** buf_in, // work around broken timestamps if (pts < 0 && in->s.start >= 0) { - pts = in->s.start; + if (pts < pv->last_pts) + { + // XXX: this should only happen if the prevous pts + // was unknown and our 3 second default duration + // overshot the next pgs pts. + // + // assign a 1 second duration + pts = pv->last_pts + 1 * 90000LL; + hb_log("[warning] decpgssub: track %d, non-monotically increasing PTS", + w->subtitle->out_track); + } + else + { + pts = in->s.start; + } } else if (pts < 0) { // XXX: a broken pts will cause us to drop this subtitle, // which is bad; use a default duration of 3 seconds + // + // A broken pts is only generated when a pgs packet + // occurs after a discontinuity and before the + // next audio or video packet which re-establishes + // timing (afaik). pts = pv->last_pts + 3 * 90000LL; hb_log("[warning] decpgssub: track %d, invalid PTS", w->subtitle->out_track); @@ -332,6 +351,7 @@ static int decsubWork( hb_work_object_t * w, hb_buffer_t ** buf_in, hb_buffer_close( &pv->list_pass_buffer ); out->s = in->s; + out->s.frametype = HB_FRAME_SUBTITLE; out->sequence = in->sequence; } out->s.start = out->s.stop = pts; @@ -348,6 +368,7 @@ static int decsubWork( hb_work_object_t * w, hb_buffer_t ** buf_in, out = hb_frame_buffer_init(AV_PIX_FMT_YUVA420P, rect->w, rect->h); + out->s.frametype = HB_FRAME_SUBTITLE; out->s.id = in->s.id; out->sequence = in->sequence; out->s.start = pts; @@ -407,6 +428,7 @@ static int decsubWork( hb_work_object_t * w, hb_buffer_t ** buf_in, { out = hb_buffer_init( 1 ); + out->s.frametype = HB_FRAME_SUBTITLE; out->s.id = in->s.id; out->s.start = pts; out->s.stop = pts; diff --git a/libhb/decssasub.c b/libhb/decssasub.c index d648f1d9d..277e3672b 100644 --- a/libhb/decssasub.c +++ b/libhb/decssasub.c @@ -33,6 +33,7 @@ struct hb_work_private_s { // If decoding to PICTURESUB format: int readOrder; + int raw; hb_job_t *job; }; @@ -336,6 +337,7 @@ static hb_buffer_t *ssa_decode_line_to_utf8( uint8_t *in_data, int in_size, int out->size = dst - out->data; // Copy metadata from the input packet to the output packet + out->s.frametype = HB_FRAME_SUBTITLE; out->s.start = in_start; out->s.stop = in_stop; out->sequence = in_sequence; @@ -401,6 +403,17 @@ static hb_buffer_t *ssa_decode_line_to_mkv_ssa( hb_work_object_t * w, uint8_t *i if ( parse_timing_from_ssa_packet( (char *) in_data, &in_start, &in_stop ) ) goto fail; + if (pv->raw) + { + out = hb_buffer_init(in_size + 3); + snprintf((char*)out->data, in_size + 3, "%s\r\n", in_data); + out->s.frametype = HB_FRAME_SUBTITLE; + out->s.start = in_start; + out->s.stop = in_stop; + out->sequence = in_sequence; + return out; + } + // Convert the SSA packet to MKV-SSA format, which is what libass expects char *mkvIn; int numPartsRead; @@ -439,6 +452,7 @@ static hb_buffer_t *ssa_decode_line_to_mkv_ssa( hb_work_object_t * w, uint8_t *i strcat( mkvIn, (char *) styleToTextFields ); out->size = strlen(mkvIn); + out->s.frametype = HB_FRAME_SUBTITLE; out->s.start = in_start; out->s.stop = in_stop; out->sequence = in_sequence; @@ -464,6 +478,11 @@ static int decssaInit( hb_work_object_t * w, hb_job_t * job ) pv = calloc( 1, sizeof( hb_work_private_t ) ); w->private_data = pv; pv->job = job; + + if (job->mux & HB_MUX_MASK_AV) + { + pv->raw = 1; + } return 0; } @@ -485,7 +504,8 @@ static int decssaWork( hb_work_object_t * w, hb_buffer_t ** buf_in, return HB_WORK_DONE; } - if ( w->subtitle->config.dest == PASSTHRUSUB && pv->job->mux == HB_MUX_MKV ) + if (w->subtitle->config.dest == PASSTHRUSUB && + (pv->job->mux & HB_MUX_MASK_MKV)) { *buf_out = ssa_to_mkv_ssa(w, in); } diff --git a/libhb/dectx3gsub.c b/libhb/dectx3gsub.c index a2231a4fb..f492040c3 100644 --- a/libhb/dectx3gsub.c +++ b/libhb/dectx3gsub.c @@ -168,6 +168,7 @@ static hb_buffer_t *tx3g_decode_to_utf8( hb_buffer_t *in ) out->size = dst - out->data; // Copy metadata from the input packet to the output packet + out->s.frametype = HB_FRAME_SUBTITLE; out->s.start = in->s.start; out->s.stop = in->s.stop; diff --git a/libhb/decutf8sub.c b/libhb/decutf8sub.c index ea6440954..0cd0513d9 100644 --- a/libhb/decutf8sub.c +++ b/libhb/decutf8sub.c @@ -31,6 +31,8 @@ static int decutf8Work(hb_work_object_t * w, // Pass the packets through without modification hb_buffer_t *out = *buf_in; + out->s.frametype = HB_FRAME_SUBTITLE; + // Warn if the subtitle's duration has not been passed through by the // demuxer, which will prevent the subtitle from displaying at all if (out->s.stop == 0) diff --git a/libhb/decvobsub.c b/libhb/decvobsub.c index 12bf94417..3b6c3cb79 100644 --- a/libhb/decvobsub.c +++ b/libhb/decvobsub.c @@ -123,6 +123,7 @@ int decsubWork( hb_work_object_t * w, hb_buffer_t ** buf_in, pv->buf = hb_buffer_init( 0xFFFF ); memcpy( pv->buf->data, in->data, in->size ); pv->buf->s.id = in->s.id; + pv->buf->s.frametype = HB_FRAME_SUBTITLE; pv->buf->sequence = in->sequence; pv->size_got = in->size; if( in->s.start >= 0 ) @@ -537,6 +538,7 @@ static hb_buffer_t * CropSubtitle( hb_work_object_t * w, uint8_t * raw ) realheight = crop[1] - crop[0] + 1; buf = hb_frame_buffer_init( AV_PIX_FMT_YUVA420P, realwidth, realheight ); + buf->s.frametype = HB_FRAME_SUBTITLE; buf->s.start = pv->pts_start; buf->s.stop = pv->pts_stop; buf->s.type = SUBTITLE_BUF; diff --git a/libhb/deinterlace.c b/libhb/deinterlace.c index a7e724c02..09b92c437 100644 --- a/libhb/deinterlace.c +++ b/libhb/deinterlace.c @@ -19,11 +19,9 @@ #include "hb.h" #include "hbffmpeg.h" #include "mpeg2dec/mpeg2.h" -#include "mcdeint.h" #include "taskset.h" // yadif_mode is a bit vector with the following flags -// Note that 2PASS should be enabled when using MCDEINT #define MODE_YADIF_ENABLE 1 #define MODE_YADIF_SPATIAL 2 #define MODE_YADIF_2PASS 4 @@ -32,9 +30,6 @@ #define YADIF_MODE_DEFAULT 0 #define YADIF_PARITY_DEFAULT -1 -#define MCDEINT_MODE_DEFAULT -1 -#define MCDEINT_QP_DEFAULT 1 - #define ABS(a) ((a) > 0 ? (a) : (-(a))) #define MIN3(a,b,c) MIN(MIN(a,b),c) #define MAX3(a,b,c) MAX(MAX(a,b),c) @@ -61,11 +56,6 @@ struct hb_filter_private_s taskset_t yadif_taskset; // Threads for Yadif - one per CPU yadif_arguments_t *yadif_arguments; // Arguments to thread for work - - int mcdeint_mode; - mcdeint_private_t mcdeint; - - //hb_buffer_t * buf_out[2]; }; static int hb_deinterlace_init( hb_filter_object_t * filter, @@ -81,7 +71,7 @@ hb_filter_object_t hb_filter_deinterlace = { .id = HB_FILTER_DEINTERLACE, .enforce_order = 1, - .name = "Deinterlace (ffmpeg or yadif/mcdeint)", + .name = "Deinterlace", .settings = NULL, .init = hb_deinterlace_init, .work = hb_deinterlace_work, @@ -336,16 +326,11 @@ static int hb_deinterlace_init( hb_filter_object_t * filter, pv->yadif_mode = YADIF_MODE_DEFAULT; pv->yadif_parity = YADIF_PARITY_DEFAULT; - pv->mcdeint_mode = MCDEINT_MODE_DEFAULT; - int mcdeint_qp = MCDEINT_QP_DEFAULT; - if( filter->settings ) { - sscanf( filter->settings, "%d:%d:%d:%d", + sscanf( filter->settings, "%d:%d", &pv->yadif_mode, - &pv->yadif_parity, - &pv->mcdeint_mode, - &mcdeint_qp ); + &pv->yadif_parity); } pv->cpu_count = hb_get_cpu_count(); @@ -384,9 +369,6 @@ static int hb_deinterlace_init( hb_filter_object_t * filter, } } } - - mcdeint_init( &pv->mcdeint, pv->mcdeint_mode, mcdeint_qp, - init->pix_fmt, init->width, init->height ); return 0; } @@ -413,8 +395,6 @@ static void hb_deinterlace_close( hb_filter_object_t * filter ) free( pv->yadif_arguments ); } - - mcdeint_close( &pv->mcdeint ); free( pv ); filter->private_data = NULL; @@ -494,7 +474,7 @@ static int hb_deinterlace_work( hb_filter_object_t * filter, tff = (pv->yadif_parity & 1) ^ 1; } - /* deinterlace both fields if mcdeint is enabled without bob */ + /* deinterlace both fields if yadif 2 pass or bob */ int frame, num_frames = 1; if ((pv->yadif_mode & MODE_YADIF_2PASS) || (pv->yadif_mode & MODE_YADIF_BOB)) @@ -506,7 +486,7 @@ static int hb_deinterlace_work( hb_filter_object_t * filter, int idx = 0; hb_buffer_t * o_buf[2] = {NULL,}; - /* Perform yadif and mcdeint filtering */ + /* Perform yadif filtering */ for( frame = 0; frame < num_frames; frame++ ) { int parity = frame ^ tff ^ 1; @@ -517,18 +497,8 @@ static int hb_deinterlace_work( hb_filter_object_t * filter, } yadif_filter(pv, o_buf[idx], parity, tff); - if (pv->mcdeint_mode >= 0) - { - if (o_buf[idx^1] == NULL) - { - o_buf[idx^1] = hb_frame_buffer_init(in->f.fmt, in->f.width, in->f.height); - } - mcdeint_filter( o_buf[idx^1], o_buf[idx], parity, &pv->mcdeint ); - idx ^= 1; - } - // If bob, add both frames - // else, add only second frame + // else, add only final frame if (( pv->yadif_mode & MODE_YADIF_BOB ) || frame == num_frames - 1) { if ( out == NULL ) @@ -550,6 +520,7 @@ static int hb_deinterlace_work( hb_filter_object_t * filter, idx ^= 1; } } + // Copy subs only to first output buffer hb_buffer_move_subs( out, pv->yadif_ref[1] ); diff --git a/libhb/dvd.c b/libhb/dvd.c index 56c1ba571..240582a52 100644 --- a/libhb/dvd.c +++ b/libhb/dvd.c @@ -173,8 +173,6 @@ static hb_title_t * hb_dvdread_title_scan( hb_dvd_t * e, int t, uint64_t min_dur ifo_handle_t * vts = NULL; int pgc_id, pgn, i; hb_chapter_t * chapter; - uint64_t duration; - float duration_correction; unsigned char unused[1024]; const char * codec_name; @@ -609,19 +607,9 @@ static hb_title_t * hb_dvdread_title_scan( hb_dvd_t * e, int t, uint64_t min_dur hb_list_add( title->list_chapter, chapter ); } - /* The durations we get for chapters aren't precise. Scale them so - the total matches the title duration */ - duration = 0; - for( i = 0; i < hb_list_count( title->list_chapter ); i++ ) - { - chapter = hb_list_item( title->list_chapter, i ); - duration += chapter->duration; - } - duration_correction = (float) title->duration / (float) duration; for( i = 0; i < hb_list_count( title->list_chapter ); i++ ) { chapter = hb_list_item( title->list_chapter, i ); - chapter->duration = duration_correction * chapter->duration; int seconds = ( chapter->duration + 45000 ) / 90000; chapter->hours = ( seconds / 3600 ); @@ -1270,8 +1258,8 @@ static int dvdtime2msec(dvd_time_t * dt) if( fps > 0 ) { - ms += ((dt->frame_u & 0x30) >> 3) * 5 + - (dt->frame_u & 0x0f) * 1000.0 / fps; + ms += (((dt->frame_u & 0x30) >> 3) * 5 + + (dt->frame_u & 0x0f)) * 1000.0 / fps; } return ms; diff --git a/libhb/dvdnav.c b/libhb/dvdnav.c index 9217f7dba..ef80bf541 100644 --- a/libhb/dvdnav.c +++ b/libhb/dvdnav.c @@ -318,7 +318,6 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t, uint64_t min_dura int count; uint64_t duration, longest; int longest_pgcn, longest_pgn, longest_pgcn_end; - float duration_correction; const char * name; const char * codec_name; @@ -758,7 +757,6 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t, uint64_t min_dura hb_log( "scan: title %d has %d chapters", t, c ); - duration = 0; count = hb_list_count( title->list_chapter ); for (i = 0; i < count; i++) { @@ -797,16 +795,11 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t, uint64_t min_dura #undef cp cell_cur = FindNextCell( pgc, cell_cur ); } - duration += chapter->duration; } - /* The durations we get for chapters aren't precise. Scale them so - the total matches the title duration */ - duration_correction = (float) title->duration / (float) duration; for( i = 0; i < hb_list_count( title->list_chapter ); i++ ) { chapter = hb_list_item( title->list_chapter, i ); - chapter->duration = duration_correction * chapter->duration; int seconds = ( chapter->duration + 45000 ) / 90000; chapter->hours = ( seconds / 3600 ); @@ -1979,7 +1972,7 @@ static int NextPgcn( ifo_handle_t *ifo, int pgcn, uint32_t pgcn_map[MAX_PGCN/32] **********************************************************************/ static void PgcWalkInit( uint32_t pgcn_map[MAX_PGCN/32] ) { - memset(pgcn_map, 0, sizeof(pgcn_map) ); + memset(pgcn_map, 0, sizeof(uint32_t) * MAX_PGCN/32); } /*********************************************************************** @@ -1998,8 +1991,8 @@ static int dvdtime2msec(dvd_time_t * dt) if( fps > 0 ) { - ms += ((dt->frame_u & 0x30) >> 3) * 5 + - (dt->frame_u & 0x0f) * 1000.0 / fps; + ms += (((dt->frame_u & 0x30) >> 3) * 5 + + (dt->frame_u & 0x0f)) * 1000.0 / fps; } return ms; diff --git a/libhb/enc_qsv.c b/libhb/enc_qsv.c new file mode 100644 index 000000000..66825baab --- /dev/null +++ b/libhb/enc_qsv.c @@ -0,0 +1,1563 @@ +/* ********************************************************************* *\ + +Copyright (C) 2013 Intel Corporation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. +- Neither the name of Intel Corporation nor the names of its contributors +may be used to endorse or promote products derived from this software +without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +\* ********************************************************************* */ + +#include "hb.h" +#include "enc_qsv.h" +#include "qsv_common.h" +#include "qsv_memory.h" +#include "h264_common.h" + +int encqsvInit( hb_work_object_t *, hb_job_t * ); +int encqsvWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** ); +void encqsvClose( hb_work_object_t * ); + +hb_work_object_t hb_encqsv = +{ + WORK_ENCQSV, + "H.264/AVC encoder (Intel QSV)", + encqsvInit, + encqsvWork, + encqsvClose +}; + +struct hb_work_private_s +{ + hb_job_t *job; + uint32_t frames_in; + uint32_t frames_out; + int64_t last_start; + + hb_qsv_param_t param; + av_qsv_space enc_space; + + mfxEncodeCtrl force_keyframe; + struct + { + int index; + int64_t start; + } next_chapter; + +#define BFRM_DELAY_MAX 16 + // for DTS generation (when MSDK API < 1.6 or VFR) + int bfrm_delay; + int bfrm_workaround; + int64_t init_pts[BFRM_DELAY_MAX + 1]; + hb_list_t *list_dts; + + int async_depth; + int max_async_depth; + + // if encode-only, system memory used + int is_sys_mem; + struct SwsContext *sws_context_to_nv12; + + // whether to expect input from VPP or from QSV decode + int is_vpp_present; + + // whether the encoder is initialized + int init_done; + + hb_list_t *delayed_processing; +}; + +// for DTS generation (when MSDK API < 1.6 or VFR) +static void hb_qsv_add_new_dts(hb_list_t *list, int64_t new_dts) +{ + if (list != NULL) + { + int64_t *item = malloc(sizeof(int64_t)); + if (item != NULL) + { + *item = new_dts; + hb_list_add(list, item); + } + } +} +static int64_t hb_qsv_pop_next_dts(hb_list_t *list) +{ + int64_t next_dts = INT64_MIN; + if (list != NULL && hb_list_count(list) > 0) + { + int64_t *item = hb_list_item(list, 0); + if (item != NULL) + { + next_dts = *item; + hb_list_rem(list, item); + free(item); + } + } + return next_dts; +} + +static const char* qsv_h264_profile_xlat(int profile) +{ + switch (profile) + { + case MFX_PROFILE_AVC_CONSTRAINED_BASELINE: + return "Constrained Baseline"; + case MFX_PROFILE_AVC_BASELINE: + return "Baseline"; + case MFX_PROFILE_AVC_EXTENDED: + return "Extended"; + case MFX_PROFILE_AVC_MAIN: + return "Main"; + case MFX_PROFILE_AVC_CONSTRAINED_HIGH: + return "Constrained High"; + case MFX_PROFILE_AVC_PROGRESSIVE_HIGH: + return "Progressive High"; + case MFX_PROFILE_AVC_HIGH: + return "High"; + case MFX_PROFILE_UNKNOWN: + default: + return NULL; + } +} + +static const char* qsv_h264_level_xlat(int level) +{ + int i; + for (i = 0; hb_h264_level_names[i] != NULL; i++) + { + if (hb_h264_level_values[i] == level) + { + return hb_h264_level_names[i]; + } + } + return NULL; +} + +int qsv_enc_init(av_qsv_context *qsv, hb_work_private_t *pv) +{ + int i = 0; + mfxStatus sts; + hb_job_t *job = pv->job; + + if (pv->init_done) + { + return 0; + } + + if (qsv == NULL) + { + if (!pv->is_sys_mem) + { + hb_error("qsv_enc_init: decode enabled but no context!"); + return 3; + } + job->qsv = qsv = av_mallocz(sizeof(av_qsv_context)); + } + + av_qsv_space *qsv_encode = qsv->enc_space; + if (qsv_encode == NULL) + { + // if only for encode + if (pv->is_sys_mem) + { + // no need to use additional sync as encode only -> single thread + // XXX: this zeroes the session handle, so call it before MFXInit + av_qsv_add_context_usage(qsv, 0); + + // initialize the session + qsv->ver.Major = AV_QSV_MSDK_VERSION_MAJOR; + qsv->ver.Minor = AV_QSV_MSDK_VERSION_MINOR; + qsv->impl = hb_qsv_impl_get_preferred(); + sts = MFXInit(qsv->impl, &qsv->ver, &qsv->mfx_session); + if (sts != MFX_ERR_NONE) + { + hb_error("qsv_enc_init: MFXInit failed (%d)", sts); + *job->die = 1; + return -1; + } + } + qsv->enc_space = qsv_encode = &pv->enc_space; + } + + if (!pv->is_sys_mem) + { + if (!pv->is_vpp_present && job->list_filter != NULL) + { + for (i = 0; i < hb_list_count(job->list_filter); i++) + { + hb_filter_object_t *filter = hb_list_item(job->list_filter, i); + if (filter->id == HB_FILTER_QSV_PRE || + filter->id == HB_FILTER_QSV_POST || + filter->id == HB_FILTER_QSV) + { + pv->is_vpp_present = 1; + break; + } + } + } + + if (pv->is_vpp_present) + { + if (qsv->vpp_space == NULL) + { + return 2; + } + for (i = 0; i < av_qsv_list_count(qsv->vpp_space); i++) + { + av_qsv_space *vpp = av_qsv_list_item(qsv->vpp_space, i); + if (!vpp->is_init_done) + { + return 2; + } + } + } + + av_qsv_space *dec_space = qsv->dec_space; + if (dec_space == NULL || !dec_space->is_init_done) + { + return 2; + } + } + else + { + pv->sws_context_to_nv12 = hb_sws_get_context(job->width, job->height, + AV_PIX_FMT_YUV420P, + job->width, job->height, + AV_PIX_FMT_NV12, + SWS_LANCZOS|SWS_ACCURATE_RND); + } + + // allocate tasks + qsv_encode->p_buf_max_size = AV_QSV_BUF_SIZE_DEFAULT; + qsv_encode->tasks = av_qsv_list_init(HAVE_THREADS); + for (i = 0; i < pv->max_async_depth; i++) + { + av_qsv_task *task = av_mallocz(sizeof(av_qsv_task)); + task->bs = av_mallocz(sizeof(mfxBitstream)); + task->bs->Data = av_mallocz(sizeof(uint8_t) * qsv_encode->p_buf_max_size); + task->bs->MaxLength = qsv_encode->p_buf_max_size; + task->bs->DataLength = 0; + task->bs->DataOffset = 0; + av_qsv_list_add(qsv_encode->tasks, task); + } + + // setup surface allocation + qsv_encode->m_mfxVideoParam.IOPattern = (pv->is_sys_mem ? + MFX_IOPATTERN_IN_SYSTEM_MEMORY : + MFX_IOPATTERN_IN_OPAQUE_MEMORY); + memset(&qsv_encode->request, 0, sizeof(mfxFrameAllocRequest) * 2); + sts = MFXVideoENCODE_QueryIOSurf(qsv->mfx_session, + &qsv_encode->m_mfxVideoParam, + &qsv_encode->request); + if (sts < MFX_ERR_NONE) // ignore warnings + { + hb_error("qsv_enc_init: MFXVideoENCODE_QueryIOSurf failed (%d)", sts); + *job->die = 1; + return -1; + } + + // allocate surfaces + if (pv->is_sys_mem) + { + qsv_encode->surface_num = FFMIN(qsv_encode->request[0].NumFrameSuggested + + pv->max_async_depth, AV_QSV_SURFACE_NUM); + if (qsv_encode->surface_num <= 0) + { + qsv_encode->surface_num = AV_QSV_SURFACE_NUM; + } + for (i = 0; i < qsv_encode->surface_num; i++) + { + qsv_encode->p_surfaces[i] = av_mallocz(sizeof(mfxFrameSurface1)); + AV_QSV_CHECK_POINTER(qsv_encode->p_surfaces[i], MFX_ERR_MEMORY_ALLOC); + memcpy(&(qsv_encode->p_surfaces[i]->Info), + &(qsv_encode->request[0].Info), sizeof(mfxFrameInfo)); + } + } + else + { + av_qsv_space *in_space = qsv->dec_space; + if (pv->is_vpp_present) + { + // we get our input from VPP instead + in_space = av_qsv_list_item(qsv->vpp_space, + av_qsv_list_count(qsv->vpp_space) - 1); + } + // introduced in API 1.3 + memset(&qsv_encode->ext_opaque_alloc, 0, sizeof(mfxExtOpaqueSurfaceAlloc)); + qsv_encode->ext_opaque_alloc.Header.BufferId = MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION; + qsv_encode->ext_opaque_alloc.Header.BufferSz = sizeof(mfxExtOpaqueSurfaceAlloc); + qsv_encode->ext_opaque_alloc.In.Surfaces = in_space->p_surfaces; + qsv_encode->ext_opaque_alloc.In.NumSurface = in_space->surface_num; + qsv_encode->ext_opaque_alloc.In.Type = qsv_encode->request[0].Type; + qsv_encode->m_mfxVideoParam.ExtParam[qsv_encode->m_mfxVideoParam.NumExtParam++] = (mfxExtBuffer*)&qsv_encode->ext_opaque_alloc; + } + + // allocate sync points + qsv_encode->sync_num = (qsv_encode->surface_num ? + FFMIN(qsv_encode->surface_num, AV_QSV_SYNC_NUM) : + AV_QSV_SYNC_NUM); + for (i = 0; i < qsv_encode->sync_num; i++) + { + qsv_encode->p_syncp[i] = av_mallocz(sizeof(av_qsv_sync)); + AV_QSV_CHECK_POINTER(qsv_encode->p_syncp[i], MFX_ERR_MEMORY_ALLOC); + qsv_encode->p_syncp[i]->p_sync = av_mallocz(sizeof(mfxSyncPoint)); + AV_QSV_CHECK_POINTER(qsv_encode->p_syncp[i]->p_sync, MFX_ERR_MEMORY_ALLOC); + } + + // initialize the encoder + sts = MFXVideoENCODE_Init(qsv->mfx_session, &qsv_encode->m_mfxVideoParam); + if (sts < MFX_ERR_NONE) // ignore warnings + { + hb_error("qsv_enc_init: MFXVideoENCODE_Init failed (%d)", sts); + *job->die = 1; + return -1; + } + qsv_encode->is_init_done = 1; + + mfxIMPL impl; + mfxVersion version; + // log actual implementation details now that we know them + if ((MFXQueryIMPL (qsv->mfx_session, &impl) == MFX_ERR_NONE) && + (MFXQueryVersion(qsv->mfx_session, &version) == MFX_ERR_NONE)) + { + hb_log("qsv_enc_init: using '%s' implementation, API: %"PRIu16".%"PRIu16"", + hb_qsv_impl_get_name(impl), version.Major, version.Minor); + } + else + { + hb_log("qsv_enc_init: MFXQueryIMPL/MFXQueryVersion failure"); + } + + pv->init_done = 1; + return 0; +} + +/*********************************************************************** + * encqsvInit + *********************************************************************** + * + **********************************************************************/ +int encqsvInit(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->is_sys_mem = !hb_qsv_decode_is_enabled(job); + pv->delayed_processing = hb_list_init(); + pv->last_start = INT64_MIN; + pv->frames_in = 0; + pv->frames_out = 0; + pv->init_done = 0; + pv->is_vpp_present = 0; + + // set up a re-usable mfxEncodeCtrl to force keyframes (e.g. for chapters) + pv->force_keyframe.QP = 0; + pv->force_keyframe.FrameType = MFX_FRAMETYPE_I|MFX_FRAMETYPE_IDR|MFX_FRAMETYPE_REF; + pv->force_keyframe.NumExtParam = 0; + pv->force_keyframe.NumPayload = 0; + pv->force_keyframe.ExtParam = NULL; + pv->force_keyframe.Payload = NULL; + + pv->next_chapter.index = 0; + pv->next_chapter.start = INT64_MIN; + + // default encoding parameters + if (hb_qsv_param_default(&pv->param, &pv->enc_space.m_mfxVideoParam)) + { + hb_error("encqsvInit: hb_qsv_param_default failed"); + return -1; + } + + // set AsyncDepth to match that of decode and VPP + pv->param.videoParam->AsyncDepth = job->qsv_async_depth; + + // enable and set colorimetry (video signal information) + pv->param.videoSignalInfo.ColourDescriptionPresent = 1; + switch (job->color_matrix_code) + { + case 4: + // custom + pv->param.videoSignalInfo.ColourPrimaries = job->color_prim; + pv->param.videoSignalInfo.TransferCharacteristics = job->color_transfer; + pv->param.videoSignalInfo.MatrixCoefficients = job->color_matrix; + break; + case 3: + // ITU BT.709 HD content + pv->param.videoSignalInfo.ColourPrimaries = HB_COLR_PRI_BT709; + pv->param.videoSignalInfo.TransferCharacteristics = HB_COLR_TRA_BT709; + pv->param.videoSignalInfo.MatrixCoefficients = HB_COLR_MAT_BT709; + break; + case 2: + // ITU BT.601 DVD or SD TV content (PAL) + pv->param.videoSignalInfo.ColourPrimaries = HB_COLR_PRI_EBUTECH; + pv->param.videoSignalInfo.TransferCharacteristics = HB_COLR_TRA_BT709; + pv->param.videoSignalInfo.MatrixCoefficients = HB_COLR_MAT_SMPTE170M; + break; + case 1: + // ITU BT.601 DVD or SD TV content (NTSC) + pv->param.videoSignalInfo.ColourPrimaries = HB_COLR_PRI_SMPTEC; + pv->param.videoSignalInfo.TransferCharacteristics = HB_COLR_TRA_BT709; + pv->param.videoSignalInfo.MatrixCoefficients = HB_COLR_MAT_SMPTE170M; + break; + default: + // detected during scan + pv->param.videoSignalInfo.ColourPrimaries = job->title->color_prim; + pv->param.videoSignalInfo.TransferCharacteristics = job->title->color_transfer; + pv->param.videoSignalInfo.MatrixCoefficients = job->title->color_matrix; + break; + } + + // parse user-specified advanced options, if present + if (job->advanced_opts != NULL && job->advanced_opts[0] != '\0') + { + hb_dict_t *options_list; + hb_dict_entry_t *option = NULL; + options_list = hb_encopts_to_dict(job->advanced_opts, job->vcodec); + while ((option = hb_dict_next(options_list, option)) != NULL) + { + switch (hb_qsv_param_parse(&pv->param, + option->key, option->value, job->vcodec)) + { + case HB_QSV_PARAM_OK: + break; + + case HB_QSV_PARAM_BAD_NAME: + hb_log("encqsvInit: hb_qsv_param_parse: bad key %s", + option->key); + break; + case HB_QSV_PARAM_BAD_VALUE: + hb_log("encqsvInit: hb_qsv_param_parse: bad value %s for key %s", + option->value, option->key); + break; + case HB_QSV_PARAM_UNSUPPORTED: + hb_log("encqsvInit: hb_qsv_param_parse: unsupported option %s", + option->key); + break; + + case HB_QSV_PARAM_ERROR: + default: + hb_log("encqsvInit: hb_qsv_param_parse: unknown error"); + break; + } + } + hb_dict_free(&options_list); + } + + // reload colorimetry in case values were set in advanced_opts + if (pv->param.videoSignalInfo.ColourDescriptionPresent) + { + job->color_matrix_code = 4; + job->color_prim = pv->param.videoSignalInfo.ColourPrimaries; + job->color_transfer = pv->param.videoSignalInfo.TransferCharacteristics; + job->color_matrix = pv->param.videoSignalInfo.MatrixCoefficients; + } + else + { + job->color_matrix_code = 0; + job->color_prim = HB_COLR_PRI_UNDEF; + job->color_transfer = HB_COLR_TRA_UNDEF; + job->color_matrix = HB_COLR_MAT_UNDEF; + } + + // sanitize values that may exceed the Media SDK variable size + int64_t vrate, vrate_base; + int64_t par_width, par_height; + hb_limit_rational64(&vrate, &vrate_base, + job->vrate, job->vrate_base, UINT32_MAX); + hb_limit_rational64(&par_width, &par_height, + job->anamorphic.par_width, + job->anamorphic.par_height, UINT16_MAX); + + // some encoding parameters are used by filters to configure their output + if (pv->param.videoParam->mfx.FrameInfo.PicStruct != MFX_PICSTRUCT_PROGRESSIVE) + { + job->qsv_enc_info.align_height = AV_QSV_ALIGN32(job->height); + } + else + { + job->qsv_enc_info.align_height = AV_QSV_ALIGN16(job->height); + } + job->qsv_enc_info.align_width = AV_QSV_ALIGN16(job->width); + job->qsv_enc_info.pic_struct = pv->param.videoParam->mfx.FrameInfo.PicStruct; + job->qsv_enc_info.is_init_done = 1; + + // encode to H.264 and set FrameInfo + pv->param.videoParam->mfx.CodecId = MFX_CODEC_AVC; + pv->param.videoParam->mfx.CodecLevel = MFX_LEVEL_UNKNOWN; + pv->param.videoParam->mfx.CodecProfile = MFX_PROFILE_UNKNOWN; + pv->param.videoParam->mfx.FrameInfo.FourCC = MFX_FOURCC_NV12; + pv->param.videoParam->mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420; + pv->param.videoParam->mfx.FrameInfo.FrameRateExtN = vrate; + pv->param.videoParam->mfx.FrameInfo.FrameRateExtD = vrate_base; + pv->param.videoParam->mfx.FrameInfo.AspectRatioW = par_width; + pv->param.videoParam->mfx.FrameInfo.AspectRatioH = par_height; + pv->param.videoParam->mfx.FrameInfo.CropX = 0; + pv->param.videoParam->mfx.FrameInfo.CropY = 0; + pv->param.videoParam->mfx.FrameInfo.CropW = job->width; + pv->param.videoParam->mfx.FrameInfo.CropH = job->height; + pv->param.videoParam->mfx.FrameInfo.PicStruct = job->qsv_enc_info.pic_struct; + pv->param.videoParam->mfx.FrameInfo.Width = job->qsv_enc_info.align_width; + pv->param.videoParam->mfx.FrameInfo.Height = job->qsv_enc_info.align_height; + + // set H.264 profile and level + if (job->h264_profile != NULL && job->h264_profile[0] != '\0' && + strcasecmp(job->h264_profile, "auto")) + { + if (!strcasecmp(job->h264_profile, "baseline")) + { + pv->param.videoParam->mfx.CodecProfile = MFX_PROFILE_AVC_BASELINE; + } + else if (!strcasecmp(job->h264_profile, "main")) + { + pv->param.videoParam->mfx.CodecProfile = MFX_PROFILE_AVC_MAIN; + } + else if (!strcasecmp(job->h264_profile, "high")) + { + pv->param.videoParam->mfx.CodecProfile = MFX_PROFILE_AVC_HIGH; + } + else + { + hb_error("encqsvInit: bad profile %s", job->h264_profile); + return -1; + } + } + if (job->h264_level != NULL && job->h264_level[0] != '\0' && + strcasecmp(job->h264_level, "auto")) + { + int err; + int i = hb_qsv_atoindex(hb_h264_level_names, job->h264_level, &err); + if (err || i >= (sizeof(hb_h264_level_values) / + sizeof(hb_h264_level_values[0]))) + { + hb_error("encqsvInit: bad level %s", job->h264_level); + return -1; + } + else if (hb_qsv_info->capabilities & HB_QSV_CAP_MSDK_API_1_6) + { + pv->param.videoParam->mfx.CodecLevel = HB_QSV_CLIP3(MFX_LEVEL_AVC_1, + MFX_LEVEL_AVC_52, + hb_h264_level_values[i]); + } + else + { + // Media SDK API < 1.6, MFX_LEVEL_AVC_52 unsupported + pv->param.videoParam->mfx.CodecLevel = HB_QSV_CLIP3(MFX_LEVEL_AVC_1, + MFX_LEVEL_AVC_51, + hb_h264_level_values[i]); + } + } + + // interlaced encoding is not always possible + if (pv->param.videoParam->mfx.FrameInfo.PicStruct != MFX_PICSTRUCT_PROGRESSIVE) + { + if (pv->param.videoParam->mfx.CodecProfile == MFX_PROFILE_AVC_CONSTRAINED_BASELINE || + pv->param.videoParam->mfx.CodecProfile == MFX_PROFILE_AVC_BASELINE || + pv->param.videoParam->mfx.CodecProfile == MFX_PROFILE_AVC_PROGRESSIVE_HIGH) + { + hb_error("encqsvInit: profile %s doesn't support interlaced encoding", + qsv_h264_profile_xlat(pv->param.videoParam->mfx.CodecProfile)); + return -1; + } + if ((pv->param.videoParam->mfx.CodecLevel >= MFX_LEVEL_AVC_1b && + pv->param.videoParam->mfx.CodecLevel <= MFX_LEVEL_AVC_2) || + (pv->param.videoParam->mfx.CodecLevel >= MFX_LEVEL_AVC_42)) + { + hb_error("encqsvInit: level %s doesn't support interlaced encoding", + qsv_h264_level_xlat(pv->param.videoParam->mfx.CodecLevel)); + return -1; + } + } + + // set rate control paremeters + if (job->vquality >= 0) + { + // introduced in API 1.1 + pv->param.videoParam->mfx.RateControlMethod = MFX_RATECONTROL_CQP; + pv->param.videoParam->mfx.QPI = HB_QSV_CLIP3(0, 51, job->vquality + pv->param.rc.cqp_offsets[0]); + pv->param.videoParam->mfx.QPP = HB_QSV_CLIP3(0, 51, job->vquality + pv->param.rc.cqp_offsets[1]); + pv->param.videoParam->mfx.QPB = HB_QSV_CLIP3(0, 51, job->vquality + pv->param.rc.cqp_offsets[2]); + } + else if (job->vbitrate > 0) + { + // sanitize lookahead + if (!(hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_LOOKAHEAD)) + { + // lookahead not supported + pv->param.rc.lookahead = 0; + } + else if (pv->param.rc.lookahead > 0 && + pv->param.videoParam->mfx.FrameInfo.PicStruct != MFX_PICSTRUCT_PROGRESSIVE) + { + // user force-enabled lookahead but we can't use it + hb_log("encqsvInit: MFX_RATECONTROL_LA not used (LookAhead is progressive-only)"); + pv->param.rc.lookahead = 0; + } + else if (pv->param.rc.lookahead < 0) + { + if (pv->param.rc.vbv_max_bitrate > 0 || + pv->param.rc.vbv_buffer_size > 0 || + pv->param.videoParam->mfx.FrameInfo.PicStruct != MFX_PICSTRUCT_PROGRESSIVE) + { + // lookahead doesn't support VBV or interlaced encoding + pv->param.rc.lookahead = 0; + } + else + { + // set automatically based on target usage + pv->param.rc.lookahead = (pv->param.videoParam->mfx.TargetUsage <= MFX_TARGETUSAGE_2); + } + } + else + { + // user force-enabled or force-disabled lookahead + pv->param.rc.lookahead = !!pv->param.rc.lookahead; + } + if (pv->param.rc.lookahead) + { + // introduced in API 1.7 + pv->param.videoParam->mfx.RateControlMethod = MFX_RATECONTROL_LA; + pv->param.videoParam->mfx.TargetKbps = job->vbitrate; + if (pv->param.rc.vbv_max_bitrate > 0 || + pv->param.rc.vbv_buffer_size > 0) + { + hb_log("encqsvInit: MFX_RATECONTROL_LA, ignoring VBV"); + } + } + else + { + // introduced in API 1.0 + if (job->vbitrate == pv->param.rc.vbv_max_bitrate) + { + pv->param.videoParam->mfx.RateControlMethod = MFX_RATECONTROL_CBR; + } + else + { + pv->param.videoParam->mfx.RateControlMethod = MFX_RATECONTROL_VBR; + } + // only set BufferSizeInKB, InitialDelayInKB and MaxKbps if we have + // them - otheriwse Media SDK will pick values for us automatically + if (pv->param.rc.vbv_buffer_size > 0) + { + if (pv->param.rc.vbv_buffer_init > 1.0) + { + pv->param.videoParam->mfx.InitialDelayInKB = (pv->param.rc.vbv_buffer_init / 8); + } + else if (pv->param.rc.vbv_buffer_init > 0.0) + { + pv->param.videoParam->mfx.InitialDelayInKB = (pv->param.rc.vbv_buffer_size * + pv->param.rc.vbv_buffer_init / 8); + } + pv->param.videoParam->mfx.BufferSizeInKB = (pv->param.rc.vbv_buffer_size / 8); + } + if (pv->param.rc.vbv_max_bitrate > 0) + { + pv->param.videoParam->mfx.MaxKbps = pv->param.rc.vbv_max_bitrate; + } + pv->param.videoParam->mfx.TargetKbps = job->vbitrate; + } + } + else + { + hb_error("encqsvInit: invalid rate control (%d, %d)", + job->vquality, job->vbitrate); + return -1; + } + + // set the keyframe interval + if (pv->param.gop.gop_pic_size < 0) + { + int rate = (int)((double)job->vrate / (double)job->vrate_base + 0.5); + if (pv->param.videoParam->mfx.RateControlMethod == MFX_RATECONTROL_CQP) + { + // ensure B-pyramid is enabled for CQP on Haswell + pv->param.gop.gop_pic_size = 32; + } + else + { + // set the keyframe interval based on the framerate + pv->param.gop.gop_pic_size = 5 * rate + 1; + } + } + pv->param.videoParam->mfx.GopPicSize = pv->param.gop.gop_pic_size; + + // sanitize some settings that affect memory consumption + if (!pv->is_sys_mem) + { + // limit these to avoid running out of resources (causes hang) + pv->param.videoParam->mfx.GopRefDist = FFMIN(pv->param.videoParam->mfx.GopRefDist, + pv->param.rc.lookahead ? 8 : 16); + pv->param.codingOption2.LookAheadDepth = FFMIN(pv->param.codingOption2.LookAheadDepth, + pv->param.rc.lookahead ? 48 - pv->param.videoParam->mfx.GopRefDist : 0); + } + else + { + // encode-only is a bit less sensitive to memory issues + pv->param.videoParam->mfx.GopRefDist = FFMIN(pv->param.videoParam->mfx.GopRefDist, 16); + pv->param.codingOption2.LookAheadDepth = FFMIN(pv->param.codingOption2.LookAheadDepth, + pv->param.rc.lookahead ? 60 : 0); + } + + if ((hb_qsv_info->capabilities & HB_QSV_CAP_H264_BPYRAMID) && + (pv->param.videoParam->mfx.CodecProfile != MFX_PROFILE_AVC_BASELINE && + pv->param.videoParam->mfx.CodecProfile != MFX_PROFILE_AVC_CONSTRAINED_HIGH && + pv->param.videoParam->mfx.CodecProfile != MFX_PROFILE_AVC_CONSTRAINED_BASELINE)) + { + int gop_ref_dist = 4; + /* + * B-pyramid is supported. + * + * Set gop_ref_dist to a power of two, >= 4 and <= GopRefDist to ensure + * Media SDK will not disable B-pyramid if we end up using it below. + */ + while (pv->param.videoParam->mfx.GopRefDist >= gop_ref_dist * 2) + { + gop_ref_dist *= 2; + } + if ((pv->param.gop.b_pyramid) && + (pv->param.videoParam->mfx.GopPicSize == 0 || + pv->param.videoParam->mfx.GopPicSize > gop_ref_dist)) + { + /* + * B-pyramid enabled and GopPicSize is long enough for gop_ref_dist. + * + * Use gop_ref_dist. GopPicSize must be a multiple of GopRefDist. + * NumRefFrame should be >= (GopRefDist / 2) and >= 3, otherwise + * Media SDK may sometimes decide to disable B-pyramid too (whereas + * sometimes it will just sanitize NumrefFrame instead). + * + * Notes: Media SDK handles the NumRefFrame == 0 case for us. + * Also, GopPicSize == 0 should always result in a value that + * does NOT cause Media SDK to disable B-pyramid, so it's OK. + */ + pv->param.videoParam->mfx.GopRefDist = gop_ref_dist; + pv->param.videoParam->mfx.GopPicSize = (pv->param.videoParam->mfx.GopPicSize / + pv->param.videoParam->mfx.GopRefDist * + pv->param.videoParam->mfx.GopRefDist); + if (pv->param.videoParam->mfx.NumRefFrame != 0) + { + pv->param.videoParam->mfx.NumRefFrame = FFMAX(pv->param.videoParam->mfx.NumRefFrame, + pv->param.videoParam->mfx.GopRefDist / 2); + pv->param.videoParam->mfx.NumRefFrame = FFMAX(pv->param.videoParam->mfx.NumRefFrame, 3); + } + } + else + { + /* + * B-pyramid disabled or not possible (GopPicSize too short). + * Sanitize gop.b_pyramid to 0 (off/disabled). + */ + pv->param.gop.b_pyramid = 0; + /* Then, adjust settings to actually disable it. */ + if (pv->param.videoParam->mfx.GopRefDist == 0) + { + /* + * GopRefDist == 0 means the value will be set by Media SDK. + * Since we can't be sure what the actual value would be, we + * have to make sure that GopRefDist is set explicitly. + */ + pv->param.videoParam->mfx.GopRefDist = gop_ref_dist - 1; + } + else if (pv->param.videoParam->mfx.GopRefDist == gop_ref_dist) + { + /* GopRefDist is compatible with Media SDK's B-pyramid. */ + if (pv->param.videoParam->mfx.GopPicSize == 0) + { + /* + * GopPicSize is unknown and could be a multiple of + * GopRefDist. Decrement the latter to disable B-pyramid. + */ + pv->param.videoParam->mfx.GopRefDist--; + } + else if (pv->param.videoParam->mfx.GopPicSize % + pv->param.videoParam->mfx.GopRefDist == 0) + { + /* + * GopPicSize is a multiple of GopRefDist. + * Increment the former to disable B-pyramid. + */ + pv->param.videoParam->mfx.GopPicSize++; + } + } + } + } + else + { + /* B-pyramid not supported. */ + pv->param.gop.b_pyramid = 0; + } + + /* + * init a dummy encode-only session to get the SPS/PPS + * and the final output settings sanitized by Media SDK + * this is fine since the actual encode will use the same + * values for all parameters relevant to the H.264 bitstream + */ + mfxStatus err; + mfxVersion version; + mfxVideoParam videoParam; + mfxExtBuffer* ExtParamArray[3]; + mfxSession session = (mfxSession)0; + mfxExtCodingOption option1_buf, *option1 = &option1_buf; + mfxExtCodingOption2 option2_buf, *option2 = &option2_buf; + mfxExtCodingOptionSPSPPS sps_pps_buf, *sps_pps = &sps_pps_buf; + version.Major = HB_QSV_MINVERSION_MAJOR; + version.Minor = HB_QSV_MINVERSION_MINOR; + err = MFXInit(hb_qsv_impl_get_preferred(), &version, &session); + if (err != MFX_ERR_NONE) + { + hb_error("encqsvInit: MFXInit failed (%d)", err); + return -1; + } + err = MFXVideoENCODE_Init(session, pv->param.videoParam); + if (err < MFX_ERR_NONE) // ignore warnings + { + hb_error("encqsvInit: MFXVideoENCODE_Init failed (%d)", err); + MFXClose(session); + return -1; + } + memset(&videoParam, 0, sizeof(mfxVideoParam)); + videoParam.ExtParam = ExtParamArray; + videoParam.NumExtParam = 0; + // introduced in API 1.3 + memset(sps_pps, 0, sizeof(mfxExtCodingOptionSPSPPS)); + sps_pps->Header.BufferId = MFX_EXTBUFF_CODING_OPTION_SPSPPS; + sps_pps->Header.BufferSz = sizeof(mfxExtCodingOptionSPSPPS); + sps_pps->SPSId = 0; + sps_pps->SPSBuffer = w->config->h264.sps; + sps_pps->SPSBufSize = sizeof(w->config->h264.sps); + sps_pps->PPSId = 0; + sps_pps->PPSBuffer = w->config->h264.pps; + sps_pps->PPSBufSize = sizeof(w->config->h264.pps); + videoParam.ExtParam[videoParam.NumExtParam++] = (mfxExtBuffer*)sps_pps; + // introduced in API 1.0 + memset(option1, 0, sizeof(mfxExtCodingOption)); + option1->Header.BufferId = MFX_EXTBUFF_CODING_OPTION; + option1->Header.BufferSz = sizeof(mfxExtCodingOption); + videoParam.ExtParam[videoParam.NumExtParam++] = (mfxExtBuffer*)option1; + // introduced in API 1.6 + memset(option2, 0, sizeof(mfxExtCodingOption2)); + option2->Header.BufferId = MFX_EXTBUFF_CODING_OPTION2; + option2->Header.BufferSz = sizeof(mfxExtCodingOption2); + if (hb_qsv_info->capabilities & HB_QSV_CAP_MSDK_API_1_6) + { + // attach to get the final output mfxExtCodingOption2 settings + videoParam.ExtParam[videoParam.NumExtParam++] = (mfxExtBuffer*)option2; + } + err = MFXVideoENCODE_GetVideoParam(session, &videoParam); + MFXVideoENCODE_Close(session); + MFXClose(session); + if (err == MFX_ERR_NONE) + { + // remove 32-bit NAL prefix (0x00 0x00 0x00 0x01) + w->config->h264.sps_length = sps_pps->SPSBufSize - 4; + memmove(w->config->h264.sps, w->config->h264.sps + 4, + w->config->h264.sps_length); + w->config->h264.pps_length = sps_pps->PPSBufSize - 4; + memmove(w->config->h264.pps, w->config->h264.pps + 4, + w->config->h264.pps_length); + } + else + { + hb_error("encqsvInit: MFXVideoENCODE_GetVideoParam failed (%d)", err); + return -1; + } + + // check whether B-frames are used + switch (videoParam.mfx.CodecProfile) + { + case MFX_PROFILE_AVC_BASELINE: + case MFX_PROFILE_AVC_CONSTRAINED_HIGH: + case MFX_PROFILE_AVC_CONSTRAINED_BASELINE: + pv->bfrm_delay = 0; + break; + default: + pv->bfrm_delay = 1; + break; + } + // sanitize + pv->bfrm_delay = FFMIN(pv->bfrm_delay, videoParam.mfx.GopRefDist - 1); + pv->bfrm_delay = FFMIN(pv->bfrm_delay, videoParam.mfx.GopPicSize - 2); + pv->bfrm_delay = FFMAX(pv->bfrm_delay, 0); + // let the muxer know whether to expect B-frames or not + job->areBframes = !!pv->bfrm_delay; + // check whether we need to generate DTS ourselves (MSDK API < 1.6 or VFR) + pv->bfrm_workaround = job->cfr != 1 || !(hb_qsv_info->capabilities & + HB_QSV_CAP_MSDK_API_1_6); + if (pv->bfrm_delay && pv->bfrm_workaround) + { + pv->bfrm_workaround = 1; + pv->list_dts = hb_list_init(); + } + else + { + pv->bfrm_workaround = 0; + pv->list_dts = NULL; + } + + // log code path and main output settings + hb_log("encqsvInit: using %s path", + pv->is_sys_mem ? "encode-only" : "full QSV"); + hb_log("encqsvInit: TargetUsage %"PRIu16" AsyncDepth %"PRIu16"", + videoParam.mfx.TargetUsage, videoParam.AsyncDepth); + hb_log("encqsvInit: GopRefDist %"PRIu16" GopPicSize %"PRIu16" NumRefFrame %"PRIu16"", + videoParam.mfx.GopRefDist, videoParam.mfx.GopPicSize, videoParam.mfx.NumRefFrame); + hb_log("encqsvInit: BFrames %s BPyramid %s", + pv->bfrm_delay ? "on" : "off", + pv->bfrm_delay && pv->param.gop.b_pyramid ? "on" : "off"); + if (videoParam.mfx.RateControlMethod == MFX_RATECONTROL_CQP) + { + char qpi[7], qpp[9], qpb[9]; + snprintf(qpi, sizeof(qpi), "QPI %"PRIu16"", videoParam.mfx.QPI); + snprintf(qpp, sizeof(qpp), " QPP %"PRIu16"", videoParam.mfx.QPP); + snprintf(qpb, sizeof(qpb), " QPB %"PRIu16"", videoParam.mfx.QPB); + hb_log("encqsvInit: RateControlMethod CQP with %s%s%s", qpi, + videoParam.mfx.GopPicSize > 1 ? qpp : "", + videoParam.mfx.GopRefDist > 1 ? qpb : ""); + } + else + { + switch (videoParam.mfx.RateControlMethod) + { + case MFX_RATECONTROL_LA: + hb_log("encqsvInit: RateControlMethod LA TargetKbps %"PRIu16" LookAheadDepth %"PRIu16"", + videoParam.mfx.TargetKbps, option2->LookAheadDepth); + break; + case MFX_RATECONTROL_CBR: + case MFX_RATECONTROL_VBR: + hb_log("encqsvInit: RateControlMethod %s TargetKbps %"PRIu16" MaxKbps %"PRIu16" BufferSizeInKB %"PRIu16" InitialDelayInKB %"PRIu16"", + videoParam.mfx.RateControlMethod == MFX_RATECONTROL_CBR ? "CBR" : "VBR", + videoParam.mfx.TargetKbps, videoParam.mfx.MaxKbps, + videoParam.mfx.BufferSizeInKB, videoParam.mfx.InitialDelayInKB); + break; + default: + hb_log("encqsvInit: invalid rate control method %"PRIu16"", + videoParam.mfx.RateControlMethod); + return -1; + } + } + switch (videoParam.mfx.FrameInfo.PicStruct) + { + case MFX_PICSTRUCT_PROGRESSIVE: + hb_log("encqsvInit: PicStruct progressive"); + break; + case MFX_PICSTRUCT_FIELD_TFF: + hb_log("encqsvInit: PicStruct top field first"); + break; + case MFX_PICSTRUCT_FIELD_BFF: + hb_log("encqsvInit: PicStruct bottom field first"); + break; + default: + hb_error("encqsvInit: invalid PicStruct value 0x%"PRIx16"", + videoParam.mfx.FrameInfo.PicStruct); + return -1; + } + hb_log("encqsvInit: CAVLC %-3s RateDistortionOpt %-3s", + hb_qsv_codingoption_get_name(option1->CAVLC), + hb_qsv_codingoption_get_name(option1->RateDistortionOpt)); + if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_BRC) + { + hb_log("encqsvInit: MBBRC %-3s ExtBRC %-3s", + hb_qsv_codingoption_get_name(option2->MBBRC), + hb_qsv_codingoption_get_name(option2->ExtBRC)); + } + if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_TRELLIS) + { + switch (option2->Trellis) + { + case MFX_TRELLIS_OFF: + hb_log("encqsvInit: Trellis off"); + break; + case MFX_TRELLIS_UNKNOWN: + hb_log("encqsvInit: Trellis unknown (auto)"); + break; + default: + hb_log("encqsvInit: Trellis on (%s%s%s)", + option2->Trellis & MFX_TRELLIS_I ? "I" : "", + option2->Trellis & MFX_TRELLIS_P ? "P" : "", + option2->Trellis & MFX_TRELLIS_B ? "B" : ""); + break; + } + } + hb_log("encqsvInit: H.264 profile %s @ level %s", + qsv_h264_profile_xlat(videoParam.mfx.CodecProfile), + qsv_h264_level_xlat (videoParam.mfx.CodecLevel)); + + // AsyncDepth has now been set and/or modified by Media SDK + pv->max_async_depth = videoParam.AsyncDepth; + pv->async_depth = 0; + + return 0; +} + +void encqsvClose( hb_work_object_t * w ) +{ + int i = 0; + hb_work_private_t * pv = w->private_data; + + hb_log( "enc_qsv done: frames: %u in, %u out", pv->frames_in, pv->frames_out ); + + // if system memory ( encode only ) additional free(s) for surfaces + if( pv && pv->job && pv->job->qsv && + pv->job->qsv->is_context_active ){ + + av_qsv_context *qsv = pv->job->qsv; + + if(qsv && qsv->enc_space){ + av_qsv_space* qsv_encode = qsv->enc_space; + if(qsv_encode->is_init_done){ + if(pv->is_sys_mem){ + if( qsv_encode && qsv_encode->surface_num > 0) + for (i = 0; i < qsv_encode->surface_num; i++){ + if( qsv_encode->p_surfaces[i]->Data.Y){ + free(qsv_encode->p_surfaces[i]->Data.Y); + qsv_encode->p_surfaces[i]->Data.Y = 0; + } + if( qsv_encode->p_surfaces[i]->Data.VU){ + free(qsv_encode->p_surfaces[i]->Data.VU); + qsv_encode->p_surfaces[i]->Data.VU = 0; + } + if(qsv_encode->p_surfaces[i]) + av_freep(qsv_encode->p_surfaces[i]); + } + qsv_encode->surface_num = 0; + + sws_freeContext(pv->sws_context_to_nv12); + } + + for (i = av_qsv_list_count(qsv_encode->tasks); i > 1; i--){ + av_qsv_task* task = av_qsv_list_item(qsv_encode->tasks,i-1); + if(task && task->bs){ + av_freep(&task->bs->Data); + av_freep(&task->bs); + av_qsv_list_rem(qsv_encode->tasks,task); + } + } + av_qsv_list_close(&qsv_encode->tasks); + + for (i = 0; i < qsv_encode->surface_num; i++){ + av_freep(&qsv_encode->p_surfaces[i]); + } + qsv_encode->surface_num = 0; + + for (i = 0; i < qsv_encode->sync_num; i++){ + av_freep(&qsv_encode->p_syncp[i]->p_sync); + av_freep(&qsv_encode->p_syncp[i]); + } + qsv_encode->sync_num = 0; + + qsv_encode->is_init_done = 0; + } + } + + if(qsv){ + // closing the commong stuff + av_qsv_context_clean(qsv); + + if(pv->is_sys_mem){ + av_freep(&qsv); + } + } + } + + if (pv != NULL) + { + if (pv->list_dts != NULL) + { + while (hb_list_count(pv->list_dts) > 0) + { + int64_t *item = hb_list_item(pv->list_dts, 0); + hb_list_rem(pv->list_dts, item); + free(item); + } + hb_list_close(&pv->list_dts); + } + } + + free( pv ); + w->private_data = NULL; +} + +int encqsvWork( 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; + av_qsv_context *qsv = job->qsv; + av_qsv_space* qsv_encode; + hb_buffer_t *last_buf = NULL; + mfxStatus sts = MFX_ERR_NONE; + int is_end = 0; + av_qsv_list* received_item = 0; + av_qsv_stage* stage = 0; + + while(1){ + int ret = qsv_enc_init(qsv, pv); + qsv = job->qsv; + qsv_encode = qsv->enc_space; + if(ret >= 2) + av_qsv_sleep(1); + else + break; + } + *buf_out = NULL; + + if (*job->die) + { + // unrecoverable error in qsv_enc_init + return HB_WORK_DONE; + } + + if( in->size <= 0 ) + { + // do delayed frames yet + *buf_in = NULL; + is_end = 1; + } + + // input from decode, as called - we always have some to proceed with + while (1) + { + { + mfxEncodeCtrl *work_control = NULL; + mfxFrameSurface1 *work_surface = NULL; + + if (!is_end) + { + if (pv->is_sys_mem) + { + int surface_idx = av_qsv_get_free_surface(qsv_encode, qsv, + &qsv_encode->request[0].Info, QSV_PART_ANY); + work_surface = qsv_encode->p_surfaces[surface_idx]; + + if (work_surface->Data.Y == NULL) + { + // if nv12 and 422 12bits per pixel + work_surface->Data.Pitch = pv->enc_space.m_mfxVideoParam.mfx.FrameInfo.Width; + work_surface->Data.Y = calloc(1, + pv->enc_space.m_mfxVideoParam.mfx.FrameInfo.Width * + pv->enc_space.m_mfxVideoParam.mfx.FrameInfo.Height); + work_surface->Data.VU = calloc(1, + pv->enc_space.m_mfxVideoParam.mfx.FrameInfo.Width * + pv->enc_space.m_mfxVideoParam.mfx.FrameInfo.Height / 2); + } + qsv_yuv420_to_nv12(pv->sws_context_to_nv12, work_surface, in); + } + else + { + received_item = in->qsv_details.qsv_atom; + stage = av_qsv_get_last_stage(received_item); + work_surface = stage->out.p_surface; + + // don't let qsv->dts_seq grow needlessly + av_qsv_dts_pop(qsv); + } + + work_surface->Data.TimeStamp = in->s.start; + + /* + * Debugging code to check that the upstream modules have generated + * a continuous, self-consistent frame stream. + */ + int64_t start = work_surface->Data.TimeStamp; + if (pv->last_start > start) + { + hb_log("encqsvWork: input continuity error, last start %"PRId64" start %"PRId64"", + pv->last_start, start); + } + pv->last_start = start; + + // for DTS generation (when MSDK API < 1.6 or VFR) + if (pv->bfrm_delay && pv->bfrm_workaround) + { + if (pv->frames_in <= BFRM_DELAY_MAX) + { + pv->init_pts[pv->frames_in] = work_surface->Data.TimeStamp; + } + if (pv->frames_in) + { + hb_qsv_add_new_dts(pv->list_dts, + work_surface->Data.TimeStamp); + } + } + + /* + * Chapters have to start with a keyframe so request that this + * frame be coded as IDR. Since there may be several frames + * buffered in the encoder, remember the timestamp so when this + * frame finally pops out of the encoder we'll mark its buffer + * as the start of a chapter. + */ + if (in->s.new_chap > 0 && job->chapter_markers) + { + if (!pv->next_chapter.index) + { + pv->next_chapter.start = work_surface->Data.TimeStamp; + pv->next_chapter.index = in->s.new_chap; + work_control = &pv->force_keyframe; + } + else + { + // however unlikely, this can happen in theory + hb_log("encqsvWork: got chapter %d before we could write chapter %d, dropping marker", + in->s.new_chap, pv->next_chapter.index); + } + // don't let 'work_loop' put a chapter mark on the wrong buffer + in->s.new_chap = 0; + } + + /* + * If interlaced encoding is requested during encoder initialization, + * but the input mfxFrameSurface1 is flagged as progressive here, + * the output bitstream will be progressive (according to MediaInfo). + * + * Assume the user knows what he's doing (say he is e.g. encoding a + * progressive-flagged source using interlaced compression - he may + * well have a good reason to do so; mis-flagged sources do exist). + */ + work_surface->Info.PicStruct = pv->enc_space.m_mfxVideoParam.mfx.FrameInfo.PicStruct; + } + else{ + work_surface = NULL; + received_item = NULL; + } + int sync_idx = av_qsv_get_free_sync( qsv_encode, qsv ); + if (sync_idx == -1) + { + hb_error("qsv: Not enough resources allocated for QSV encode"); + return 0; + } + av_qsv_task *task = av_qsv_list_item( qsv_encode->tasks, pv->async_depth ); + + for (;;) + { + // Encode a frame asychronously (returns immediately) + sts = MFXVideoENCODE_EncodeFrameAsync(qsv->mfx_session, + work_control, work_surface, task->bs, + qsv_encode->p_syncp[sync_idx]->p_sync); + + if (MFX_ERR_MORE_DATA == sts || (MFX_ERR_NONE <= sts && MFX_WRN_DEVICE_BUSY != sts)) + if (work_surface && !pv->is_sys_mem) + ff_qsv_atomic_dec(&work_surface->Data.Locked); + + if( MFX_ERR_MORE_DATA == sts ){ + ff_qsv_atomic_dec(&qsv_encode->p_syncp[sync_idx]->in_use); + if(work_surface && received_item) + hb_list_add(pv->delayed_processing, received_item); + break; + } + + AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + if (MFX_ERR_NONE <= sts /*&& !syncpE*/) // repeat the call if warning and no output + { + if (MFX_WRN_DEVICE_BUSY == sts){ + av_qsv_sleep(10); // wait if device is busy + continue; + } + + av_qsv_stage* new_stage = av_qsv_stage_init(); + new_stage->type = AV_QSV_ENCODE; + new_stage->in.p_surface = work_surface; + new_stage->out.sync = qsv_encode->p_syncp[sync_idx]; + + new_stage->out.p_bs = task->bs;//qsv_encode->bs; + task->stage = new_stage; + + pv->async_depth++; + + if(received_item){ + av_qsv_add_stagee( &received_item, new_stage,HAVE_THREADS ); + } + else{ + // flushing the end + int pipe_idx = av_qsv_list_add( qsv->pipes, av_qsv_list_init(HAVE_THREADS) ); + av_qsv_list* list_item = av_qsv_list_item( qsv->pipes, pipe_idx ); + av_qsv_add_stagee( &list_item, new_stage,HAVE_THREADS ); + } + + int i = 0; + for(i=hb_list_count(pv->delayed_processing); i > 0;i--){ + hb_list_t *item = hb_list_item(pv->delayed_processing,i-1); + if(item){ + hb_list_rem(pv->delayed_processing,item); + av_qsv_flush_stages(qsv->pipes, &item); + } + } + + break; + } + + ff_qsv_atomic_dec(&qsv_encode->p_syncp[sync_idx]->in_use); + + if (MFX_ERR_NOT_ENOUGH_BUFFER == sts) + DEBUG_ASSERT( 1,"The bitstream buffer size is insufficient." ); + + break; + } + } + + buf = NULL; + + do{ + + if(pv->async_depth==0) break; + + // working properly with sync depth approach of MediaSDK OR flushing, if at the end + if( (pv->async_depth >= pv->max_async_depth) || is_end ){ + + pv->async_depth--; + + av_qsv_task *task = av_qsv_list_item( qsv_encode->tasks, 0 ); + av_qsv_stage* stage = task->stage; + av_qsv_list* this_pipe = av_qsv_pipe_by_stage(qsv->pipes,stage); + sts = MFX_ERR_NONE; + + // only here we need to wait on operation been completed, therefore SyncOperation is used, + // after this step - we continue to work with bitstream, muxing ... + av_qsv_wait_on_sync( qsv,stage ); + + if(task->bs->DataLength>0){ + av_qsv_flush_stages( qsv->pipes, &this_pipe ); + + // see nal_encode + buf = hb_video_buffer_init( job->width, job->height ); + buf->size = 0; + buf->s.frametype = 0; + + // maping of FrameType(s) + if(task->bs->FrameType & MFX_FRAMETYPE_IDR ) buf->s.frametype = HB_FRAME_IDR; + else + if(task->bs->FrameType & MFX_FRAMETYPE_I ) buf->s.frametype = HB_FRAME_I; + else + if(task->bs->FrameType & MFX_FRAMETYPE_P ) buf->s.frametype = HB_FRAME_P; + else + if(task->bs->FrameType & MFX_FRAMETYPE_B ) buf->s.frametype = HB_FRAME_B; + + if(task->bs->FrameType & MFX_FRAMETYPE_REF ) buf->s.flags = HB_FRAME_REF; + + parse_nalus(task->bs->Data + task->bs->DataOffset,task->bs->DataLength, buf, pv->frames_out); + + if ( last_buf == NULL ) + *buf_out = buf; + else + last_buf->next = buf; + last_buf = buf; + + // simple for now but check on TimeStampCalc from MSDK + int64_t duration = ((double)pv->enc_space.m_mfxVideoParam.mfx.FrameInfo.FrameRateExtD / + (double)pv->enc_space.m_mfxVideoParam.mfx.FrameInfo.FrameRateExtN) * 90000.; + + // start -> PTS + // renderOffset -> DTS + buf->s.start = buf->s.renderOffset = task->bs->TimeStamp; + buf->s.stop = buf->s.start + duration; + buf->s.duration = duration; + if (pv->bfrm_delay) + { + if (!pv->bfrm_workaround) + { + buf->s.renderOffset = task->bs->DecodeTimeStamp; + } + else + { + // MSDK API < 1.6 or VFR, so generate our own DTS + if ((pv->frames_out == 0) && + (hb_qsv_info->capabilities & HB_QSV_CAP_MSDK_API_1_6) && + (hb_qsv_info->capabilities & HB_QSV_CAP_H264_BPYRAMID)) + { + // with B-pyramid, the delay may be more than 1 frame, + // so compute the actual delay based on the initial DTS + // provided by MSDK; also, account for rounding errors + // (e.g. 24000/1001 fps @ 90kHz -> 3753.75 ticks/frame) + pv->bfrm_delay = ((task->bs->TimeStamp - + task->bs->DecodeTimeStamp + + (duration / 2)) / duration); + pv->bfrm_delay = FFMAX(pv->bfrm_delay, 1); + pv->bfrm_delay = FFMIN(pv->bfrm_delay, BFRM_DELAY_MAX); + // check whether b_pyramid is respected, log if needed + if ((pv->param.gop.b_pyramid != 0 && pv->bfrm_delay <= 1) || + (pv->param.gop.b_pyramid == 0 && pv->bfrm_delay >= 2)) + { + hb_log("encqsvWork: b_pyramid %d not respected (delay: %d)", + pv->param.gop.b_pyramid, pv->bfrm_delay); + } + } + /* + * Generate VFR-compatible output DTS based on input PTS. + * + * Depends on the B-frame delay: + * + * 0: ipts0, ipts1, ipts2... + * 1: ipts0 - ipts1, ipts1 - ipts1, ipts1, ipts2... + * 2: ipts0 - ipts2, ipts1 - ipts2, ipts2 - ipts2, ipts1... + * ...and so on. + */ + if (pv->frames_out <= pv->bfrm_delay) + { + buf->s.renderOffset = (pv->init_pts[pv->frames_out] - + pv->init_pts[pv->bfrm_delay]); + } + else + { + buf->s.renderOffset = hb_qsv_pop_next_dts(pv->list_dts); + } + } + + /* + * In the MP4 container, DT(0) = STTS(0) = 0. + * + * Which gives us: + * CT(0) = CTTS(0) + STTS(0) = CTTS(0) = PTS(0) - DTS(0) + * When DTS(0) < PTS(0), we then have: + * CT(0) > 0 for video, but not audio (breaks A/V sync). + * + * This is typically solved by writing an edit list shifting + * video samples by the initial delay, PTS(0) - DTS(0). + * + * See: + * ISO/IEC 14496-12:2008(E), ISO base media file format + * - 8.6.1.2 Decoding Time to Sample Box + */ + if (w->config->h264.init_delay == 0 && buf->s.renderOffset < 0) + { + w->config->h264.init_delay = -buf->s.renderOffset; + } + } + + /* + * If we have a chapter marker pending and this frame's + * presentation time stamp is at or after the marker's time stamp, + * use this as the chapter start. + */ + if (pv->next_chapter.index && buf->s.frametype == HB_FRAME_IDR && + pv->next_chapter.start <= buf->s.start) + { + buf->s.new_chap = pv->next_chapter.index; + pv->next_chapter.index = 0; + } + + // shift for fifo + if(pv->async_depth){ + av_qsv_list_rem(qsv_encode->tasks,task); + av_qsv_list_add(qsv_encode->tasks,task); + } + + task->bs->DataLength = 0; + task->bs->DataOffset = 0; + task->bs->MaxLength = qsv_encode->p_buf_max_size; + task->stage = 0; + pv->frames_out++; + } + } + }while(is_end); + + + if(is_end){ + if( !buf && MFX_ERR_MORE_DATA == sts ) + break; + + } + else + break; + + } + + if(!is_end) + ++pv->frames_in; + + if(is_end){ + *buf_in = NULL; + if(last_buf){ + last_buf->next = in; + } + else + *buf_out = in; + return HB_WORK_DONE; + } + else{ + return HB_WORK_OK; + } +} + +int nal_find_start_code(uint8_t** pb, size_t* size){ + if ((int) *size < 4 ) + return 0; + + // find start code by MSDK , see ff_prefix_code[] + while ((4 <= *size) && + ((0 != (*pb)[0]) || + (0 != (*pb)[1]) || + (1 != (*pb)[2]) )) + { + *pb += 1; + *size -= 1; + } + + if (4 <= *size) + return (((*pb)[0] << 24) | ((*pb)[1] << 16) | ((*pb)[2] << 8) | ((*pb)[3])); + + return 0; +} + +void parse_nalus(uint8_t *nal_inits, size_t length, hb_buffer_t *buf, uint32_t frame_num){ + uint8_t *offset = nal_inits; + size_t size = length; + + if( nal_find_start_code(&offset,&size) == 0 ) + size = 0; + + while( size > 0 ){ + + uint8_t* current_nal = offset + sizeof(ff_prefix_code)-1; + uint8_t *next_offset = offset + sizeof(ff_prefix_code); + size_t next_size = size - sizeof(ff_prefix_code); + size_t current_size = next_size; + if( nal_find_start_code(&next_offset,&next_size) == 0 ){ + size = 0; + current_size += 1; + } + else{ + current_size -= next_size; + if( next_offset > 0 && *(next_offset-1) != 0 ) + current_size += 1; + } + { + char size_position[4] = {0,0,0,0}; + size_position[1] = (current_size >> 24) & 0xFF; + size_position[1] = (current_size >> 16) & 0xFF; + size_position[2] = (current_size >> 8) & 0xFF; + size_position[3] = current_size & 0xFF; + + memcpy(buf->data + buf->size,&size_position ,sizeof(size_position)); + buf->size += sizeof(size_position); + + memcpy(buf->data + buf->size,current_nal ,current_size); + buf->size += current_size; + } + + if(size){ + size = next_size; + offset = next_offset; + } + } +} diff --git a/libhb/enc_qsv.h b/libhb/enc_qsv.h new file mode 100644 index 000000000..9d27347cd --- /dev/null +++ b/libhb/enc_qsv.h @@ -0,0 +1,38 @@ +/* ********************************************************************* *\ + +Copyright (C) 2013 Intel Corporation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. +- Neither the name of Intel Corporation nor the names of its contributors +may be used to endorse or promote products derived from this software +without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +\* ********************************************************************* */ + +#ifndef ENC_QSV_H +#define ENC_QSV_H + +#include "hb.h" +#include "qsv_common.h" + +int nal_find_start_code(uint8_t** pb, size_t* size); +void parse_nalus( uint8_t *nal_inits, size_t length, hb_buffer_t *buf, uint32_t frame_num); + +#endif // ENC_QSV_H diff --git a/libhb/encavcodec.c b/libhb/encavcodec.c index dcb19da34..f8f9d4796 100644 --- a/libhb/encavcodec.c +++ b/libhb/encavcodec.c @@ -39,8 +39,7 @@ struct hb_work_private_s struct { int64_t start; - int64_t stop; - int64_t renderOffset; + int64_t duration; } frame_info[FRAME_INFO_SIZE]; }; @@ -209,7 +208,7 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job ) job->anamorphic.par_width, job->anamorphic.par_height ); } - if( job->mux & HB_MUX_MP4 ) + if( job->mux & HB_MUX_MASK_MP4 ) { context->flags |= CODEC_FLAG_GLOBAL_HEADER; } @@ -268,7 +267,7 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job ) { job->areBframes = 1; } - if( ( job->mux & HB_MUX_MP4 ) && job->pass != 1 ) + if( ( job->mux & HB_MUX_MASK_MP4 ) && job->pass != 1 ) { w->config->mpeg4.length = context->extradata_size; memcpy( w->config->mpeg4.bytes, context->extradata, @@ -309,7 +308,7 @@ static void save_frame_info( hb_work_private_t * pv, hb_buffer_t * in ) { int i = pv->frameno_in & FRAME_INFO_MASK; pv->frame_info[i].start = in->s.start; - pv->frame_info[i].stop = in->s.stop; + pv->frame_info[i].duration = in->s.stop - in->s.start; } static int64_t get_frame_start( hb_work_private_t * pv, int64_t frameno ) @@ -318,10 +317,10 @@ static int64_t get_frame_start( hb_work_private_t * pv, int64_t frameno ) return pv->frame_info[i].start; } -static int64_t get_frame_stop( hb_work_private_t * pv, int64_t frameno ) +static int64_t get_frame_duration( hb_work_private_t * pv, int64_t frameno ) { int i = frameno & FRAME_INFO_MASK; - return pv->frame_info[i].stop; + return pv->frame_info[i].duration; } static void compute_dts_offset( hb_work_private_t * pv, hb_buffer_t * buf ) @@ -469,10 +468,11 @@ int encavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in, else { int64_t frameno = pkt.pts; - buf->size = pkt.size; - buf->s.start = get_frame_start( pv, frameno ); - buf->s.stop = get_frame_stop( pv, frameno ); - buf->s.flags &= ~HB_FRAME_REF; + buf->size = pkt.size; + buf->s.start = get_frame_start( pv, frameno ); + buf->s.duration = get_frame_duration( pv, frameno ); + buf->s.stop = buf->s.stop + buf->s.duration; + buf->s.flags &= ~HB_FRAME_REF; switch ( pv->context->coded_frame->pict_type ) { case AV_PICTURE_TYPE_P: diff --git a/libhb/encavcodecaudio.c b/libhb/encavcodecaudio.c index e24eaca32..44c3be75d 100644 --- a/libhb/encavcodecaudio.c +++ b/libhb/encavcodecaudio.c @@ -243,6 +243,9 @@ static int encavcodecaInit(hb_work_object_t *w, hb_job_t *job) w->config->extradata.length = context->extradata_size; } + audio->config.out.delay = av_rescale_q(context->delay, context->time_base, + (AVRational){1, 90000}); + return 0; } @@ -388,21 +391,14 @@ static hb_buffer_t* Encode(hb_work_object_t *w) if (got_packet && pkt.size) { out->size = pkt.size; - // The output pts from libav is in context->time_base. Convert it back // to our timebase. - // - // Also account for the "delay" factor that libav seems to arbitrarily - // subtract from the packet. Not sure WTH they think they are doing by - // offsetting the value in a negative direction. - out->s.start = av_rescale_q(pv->context->delay + pkt.pts, - pv->context->time_base, - (AVRational){1, 90000}); - - out->s.stop = out->s.start + (90000 * pv->samples_per_frame / - audio->config.out.samplerate); - - out->s.type = AUDIO_BUF; + out->s.start = av_rescale_q(pkt.pts, pv->context->time_base, + (AVRational){1, 90000}); + out->s.duration = (double)90000 * pv->samples_per_frame / + audio->config.out.samplerate; + out->s.stop = out->s.start + out->s.duration; + out->s.type = AUDIO_BUF; out->s.frametype = HB_FRAME_AUDIO; } else diff --git a/libhb/encfaac.c b/libhb/encfaac.c index ffdddc8d4..551a7ea01 100644 --- a/libhb/encfaac.c +++ b/libhb/encfaac.c @@ -7,6 +7,7 @@ For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html */ +#ifdef USE_FAAC #include "hb.h" #include "audio_remap.h" @@ -200,12 +201,13 @@ static hb_buffer_t * Encode( hb_work_object_t * w ) { hb_buffer_t * buf = hb_buffer_init( size ); memcpy( buf->data, pv->obuf, size ); - buf->size = size; - buf->s.start = pv->pts; - pv->pts += pv->framedur; - buf->s.stop = pv->pts; - buf->s.type = AUDIO_BUF; + buf->size = size; + buf->s.start = pv->pts; + buf->s.duration = pv->framedur; + buf->s.stop = buf->s.start + buf->s.duration; + buf->s.type = AUDIO_BUF; buf->s.frametype = HB_FRAME_AUDIO; + pv->pts += pv->framedur; return buf; } return NULL; @@ -286,4 +288,4 @@ int encfaacWork( hb_work_object_t * w, hb_buffer_t ** buf_in, return HB_WORK_OK; } - +#endif // USE_FAAC diff --git a/libhb/enclame.c b/libhb/enclame.c index 2858f6078..6cb4ab3a3 100644 --- a/libhb/enclame.c +++ b/libhb/enclame.c @@ -145,9 +145,10 @@ static hb_buffer_t * Encode( hb_work_object_t * w ) } } - buf = hb_buffer_init( pv->output_bytes ); - buf->s.start = pts + 90000 * pos / pv->out_discrete_channels / sizeof( float ) / audio->config.out.samplerate; - buf->s.stop = buf->s.start + 90000 * 1152 / audio->config.out.samplerate; + buf = hb_buffer_init( pv->output_bytes ); + buf->s.start = pts + 90000 * pos / pv->out_discrete_channels / sizeof( float ) / audio->config.out.samplerate; + buf->s.duration = (double)90000 * 1152 / audio->config.out.samplerate; + buf->s.stop = buf->s.start + buf->s.duration; pv->pts = buf->s.stop; buf->size = lame_encode_buffer_float( pv->lame, samples[0], samples[1], diff --git a/libhb/enctheora.c b/libhb/enctheora.c index 07fdb7f95..36fd9e98a 100644 --- a/libhb/enctheora.c +++ b/libhb/enctheora.c @@ -178,17 +178,17 @@ int enctheoraInit( hb_work_object_t * w, hb_job_t * job ) th_comment_init( &tc ); - th_encode_flushheader( pv->ctx, &tc, &op ); - memcpy(w->config->theora.headers[0], &op, sizeof(op)); - memcpy(w->config->theora.headers[0] + sizeof(op), op.packet, op.bytes ); + ogg_packet *header; - th_encode_flushheader( pv->ctx, &tc, &op ); - memcpy(w->config->theora.headers[1], &op, sizeof(op)); - memcpy(w->config->theora.headers[1] + sizeof(op), op.packet, op.bytes ); - - th_encode_flushheader( pv->ctx, &tc, &op ); - memcpy(w->config->theora.headers[2], &op, sizeof(op)); - memcpy(w->config->theora.headers[2] + sizeof(op), op.packet, op.bytes ); + int ii; + for (ii = 0; ii < 3; ii++) + { + th_encode_flushheader( pv->ctx, &tc, &op ); + header = (ogg_packet*)w->config->theora.headers[ii]; + memcpy(header, &op, sizeof(op)); + header->packet = w->config->theora.headers[ii] + sizeof(ogg_packet); + memcpy(header->packet, op.packet, op.bytes ); + } th_comment_clear( &tc ); @@ -362,15 +362,15 @@ int enctheoraWork( hb_work_object_t * w, hb_buffer_t ** buf_in, } th_encode_packetout( pv->ctx, 0, &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 = hb_buffer_init(op.bytes); + memcpy(buf->data, op.packet, op.bytes); buf->f.fmt = AV_PIX_FMT_YUV420P; buf->f.width = frame_width; buf->f.height = frame_height; buf->s.frametype = ( th_packet_iskeyframe(&op) ) ? HB_FRAME_KEY : HB_FRAME_REF; - buf->s.start = in->s.start; - buf->s.stop = in->s.stop; + buf->s.start = in->s.start; + buf->s.stop = in->s.stop; + buf->s.duration = in->s.stop - in->s.start; *buf_out = buf; diff --git a/libhb/encvorbis.c b/libhb/encvorbis.c index e75bce622..c81b44d76 100644 --- a/libhb/encvorbis.c +++ b/libhb/encvorbis.c @@ -114,11 +114,13 @@ int encvorbisInit(hb_work_object_t *w, hb_job_t *job) /* get the 3 headers */ vorbis_analysis_headerout(&pv->vd, &pv->vc, &header[0], &header[1], &header[2]); + ogg_packet *pheader; for (i = 0; i < 3; i++) { - memcpy(w->config->vorbis.headers[i], &header[i], sizeof(ogg_packet)); - memcpy(w->config->vorbis.headers[i] + sizeof(ogg_packet), - header[i].packet, header[i].bytes); + pheader = (ogg_packet*)w->config->theora.headers[i]; + memcpy(pheader, &header[i], sizeof(ogg_packet)); + pheader->packet = w->config->theora.headers[i] + sizeof(ogg_packet); + memcpy(pheader->packet, header[i].packet, header[i].bytes ); } pv->input_samples = pv->out_discrete_channels * OGGVORBIS_FRAME_SIZE; @@ -180,10 +182,8 @@ static hb_buffer_t * Flush( hb_work_object_t * w ) if( vorbis_bitrate_flushpacket( &pv->vd, &op ) ) { - buf = hb_buffer_init( sizeof( ogg_packet ) + op.bytes ); - memcpy( buf->data, &op, sizeof( ogg_packet ) ); - memcpy( buf->data + sizeof( ogg_packet ), op.packet, - op.bytes ); + buf = hb_buffer_init( op.bytes ); + memcpy( buf->data, op.packet, op.bytes ); blocksize = vorbis_packet_blocksize(&pv->vi, &op); buf->s.type = AUDIO_BUF; @@ -191,6 +191,7 @@ static hb_buffer_t * Flush( hb_work_object_t * w ) buf->s.start = (int64_t)(vorbis_granule_time(&pv->vd, op.granulepos) * 90000); buf->s.stop = (int64_t)(vorbis_granule_time(&pv->vd, (pv->prev_blocksize + blocksize)/4 + op.granulepos) * 90000); + buf->s.duration = buf->s.stop - buf->s.start; /* The stop time isn't accurate for the first ~3 packets, as the actual blocksize depends on the previous _and_ current packets. */ pv->prev_blocksize = blocksize; return buf; diff --git a/libhb/encx264.c b/libhb/encx264.c index df978206a..6f91c8b2b 100644 --- a/libhb/encx264.c +++ b/libhb/encx264.c @@ -90,13 +90,30 @@ int encx264Init( hb_work_object_t * w, hb_job_t * job ) return 1; } + /* If the PSNR or SSIM tunes are in use, enable the relevant metric */ + if (job->x264_tune != NULL && job->x264_tune[0] != '\0') + { + char *tmp = strdup(job->x264_tune); + char *tok = strtok(tmp, ",./-+"); + do + { + if (!strncasecmp(tok, "psnr", 4)) + { + param.analyse.b_psnr = 1; + break; + } + if (!strncasecmp(tok, "ssim", 4)) + { + param.analyse.b_ssim = 1; + break; + } + } + while ((tok = strtok(NULL, ",./-+")) != NULL); + free(tmp); + } + /* Some HandBrake-specific defaults; users can override them * using the advanced_opts string. */ - - /* Enable metrics */ - param.analyse.b_psnr = 1; - param.analyse.b_ssim = 1; - if( job->pass == 2 && job->cfr != 1 ) { hb_interjob_t * interjob = hb_interjob_get( job->h ); @@ -389,9 +406,9 @@ static hb_buffer_t *nal_encode( hb_work_object_t *w, x264_picture_t *pic_out, buf->s.frametype = 0; // use the pts to get the original frame's duration. - int64_t duration = get_frame_duration( pv, pic_out->i_pts ); - buf->s.start = pic_out->i_pts; - buf->s.stop = pic_out->i_pts + duration; + buf->s.duration = get_frame_duration( pv, pic_out->i_pts ); + buf->s.start = pic_out->i_pts; + buf->s.stop = buf->s.start + buf->s.duration; buf->s.renderOffset = pic_out->i_dts; if ( !w->config->h264.init_delay && pic_out->i_dts < 0 ) { diff --git a/libhb/encx264.h b/libhb/encx264.h index b0ff8b9ca..63fa1e04a 100644 --- a/libhb/encx264.h +++ b/libhb/encx264.h @@ -8,10 +8,7 @@ */ #include "x264.h" - -static const char * const hb_h264_profile_names[] = { "auto", "high", "main", "baseline", NULL, }; -static const char * const hb_h264_level_names[] = { "auto", "1.0", "1b", "1.1", "1.2", "1.3", "2.0", "2.1", "2.2", "3.0", "3.1", "3.2", "4.0", "4.1", "4.2", "5.0", "5.1", "5.2", NULL, }; -static const int const hb_h264_level_values[] = { -1, 10, 9, 11, 12, 13, 20, 21, 22, 30, 31, 32, 40, 41, 42, 50, 51, 52, 0, }; +#include "h264_common.h" /* x264 preferred option names (left) and synonyms (right). * The "preferred" names match names used in x264's param2string function more diff --git a/libhb/fifo.c b/libhb/fifo.c index 2d792199e..bd1a45e40 100644 --- a/libhb/fifo.c +++ b/libhb/fifo.c @@ -324,6 +324,9 @@ hb_buffer_t * hb_buffer_init_internal( int size , int needsMapped ) b->alloc = buffer_pool->buffer_size; b->size = size; b->data = data; + b->s.start = -1; + b->s.stop = -1; + b->s.renderOffset = -1; #ifdef USE_OPENCL b->cl.buffer = buffer; b->cl.last_event = last_event; @@ -383,6 +386,9 @@ hb_buffer_t * hb_buffer_init_internal( int size , int needsMapped ) buffers.allocated += b->alloc; hb_unlock(buffers.lock); } + b->s.start = -1; + b->s.stop = -1; + b->s.renderOffset = -1; return b; } @@ -438,6 +444,10 @@ hb_buffer_t * hb_buffer_dup( const hb_buffer_t * src ) hb_buffer_init_planes( buf ); } +#ifdef USE_QSV + memcpy(&buf->qsv_details, &src->qsv_details, sizeof(src->qsv_details)); +#endif + return buf; } @@ -461,7 +471,7 @@ int hb_buffer_copy(hb_buffer_t * dst, const hb_buffer_t * src) static void hb_buffer_init_planes_internal( hb_buffer_t * b, uint8_t * has_plane ) { uint8_t * plane = b->data; - int p, tot = 0; + int p; for( p = 0; p < 4; p++ ) { @@ -474,7 +484,6 @@ static void hb_buffer_init_planes_internal( hb_buffer_t * b, uint8_t * has_plane b->plane[p].height = hb_image_height( b->f.fmt, b->f.height, p ); b->plane[p].size = b->plane[p].stride * b->plane[p].height_stride; plane += b->plane[p].size; - tot += b->plane[p].size; } } } @@ -560,6 +569,7 @@ void hb_video_buffer_realloc( hb_buffer_t * buf, int width, int height ) buf->f.width = width; buf->f.height = height; + buf->size = size; hb_buffer_init_planes_internal( buf, has_plane ); } @@ -639,6 +649,11 @@ void hb_buffer_move_subs( hb_buffer_t * dst, hb_buffer_t * src ) // Note that dst takes ownership of the subtitles dst->sub = src->sub; src->sub = NULL; + +#ifdef USE_QSV + memcpy(&dst->qsv_details, &src->qsv_details, sizeof(src->qsv_details)); +#endif + } hb_fifo_t * hb_fifo_init( int capacity, int thresh ) diff --git a/libhb/h264_common.h b/libhb/h264_common.h new file mode 100644 index 000000000..febe1965f --- /dev/null +++ b/libhb/h264_common.h @@ -0,0 +1,17 @@ +/* h264_common.h + + Copyright (c) 2003-2012 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 + */ + +#ifndef HB_H264_COMMON_H +#define HB_H264_COMMON_H + +static const char * const hb_h264_profile_names[] = { "auto", "high", "main", "baseline", NULL, }; +static const char * const hb_h264_level_names[] = { "auto", "1.0", "1b", "1.1", "1.2", "1.3", "2.0", "2.1", "2.2", "3.0", "3.1", "3.2", "4.0", "4.1", "4.2", "5.0", "5.1", "5.2", NULL, }; +static const int const hb_h264_level_values[] = { -1, 10, 9, 11, 12, 13, 20, 21, 22, 30, 31, 32, 40, 41, 42, 50, 51, 52, 0, }; + +#endif //HB_H264_COMMON_H diff --git a/libhb/hb.c b/libhb/hb.c index f36c95311..f6e3cb0e0 100644 --- a/libhb/hb.c +++ b/libhb/hb.c @@ -13,6 +13,10 @@ #include <unistd.h> #include <fcntl.h> +#ifdef USE_QSV +#include "qsv_common.h" +#endif + #if defined( SYS_MINGW ) #include <io.h> #if defined( PTW32_STATIC_LIB ) @@ -517,7 +521,7 @@ hb_handle_t * hb_init_dl( int verbose, int update_check ) h->main_thread = hb_thread_init( "libhb", thread_func, h, HB_NORMAL_PRIORITY ); - return h; + return h; } @@ -616,6 +620,22 @@ void hb_scan( hb_handle_t * h, const char * path, int title_index, hb_title_close( &title ); } +#ifdef USE_QSV + /* Print QSV info here so that it's in all scan and encode logs */ + hb_qsv_info_print(); +#endif + + /* Print CPU info here so that it's in all scan and encode logs */ + hb_log("hb_scan: CPU count: %i", hb_get_cpu_count()); + if (hb_get_cpu_name() != NULL) + { + hb_log("hb_scan: CPU name: %s", hb_get_cpu_name()); + } + if (hb_get_cpu_platform_name() != NULL) + { + hb_log("hb_scan: CPU type: %s", hb_get_cpu_platform_name()); + } + hb_log( "hb_scan: path=%s, title_index=%d", path, title_index ); h->scan_thread = hb_scan_init( h, &h->scan_die, path, title_index, &h->title_set, preview_count, @@ -1623,6 +1643,15 @@ int hb_global_init() return -1; } +#ifdef USE_QSV + result = hb_qsv_info_init(); + if (result < 0) + { + hb_error("hb_qsv_info_init failed!"); + return -1; + } +#endif + /* libavcodec */ hb_avcodec_init(); @@ -1650,11 +1679,16 @@ int hb_global_init() hb_register(&hb_encca_aac); hb_register(&hb_encca_haac); #endif +#ifdef USE_FAAC hb_register(&hb_encfaac); +#endif hb_register(&hb_enclame); hb_register(&hb_enctheora); hb_register(&hb_encvorbis); hb_register(&hb_encx264); +#ifdef USE_QSV + hb_register(&hb_encqsv); +#endif hb_common_global_init(); diff --git a/libhb/internal.h b/libhb/internal.h index adddbe58b..e4d5ed71c 100644 --- a/libhb/internal.h +++ b/libhb/internal.h @@ -83,14 +83,15 @@ struct hb_buffer_s uint8_t discontinuity; int new_chap; // Video packets: if non-zero, is the index of the chapter whose boundary was crossed - #define HB_FRAME_IDR 0x01 - #define HB_FRAME_I 0x02 - #define HB_FRAME_AUDIO 0x04 - #define HB_FRAME_P 0x10 - #define HB_FRAME_B 0x20 - #define HB_FRAME_BREF 0x40 - #define HB_FRAME_KEY 0x0F - #define HB_FRAME_REF 0xF0 + #define HB_FRAME_IDR 0x01 + #define HB_FRAME_I 0x02 + #define HB_FRAME_AUDIO 0x04 + #define HB_FRAME_SUBTITLE 0x08 + #define HB_FRAME_P 0x10 + #define HB_FRAME_B 0x20 + #define HB_FRAME_BREF 0x40 + #define HB_FRAME_KEY 0x0F + #define HB_FRAME_REF 0xF0 uint8_t frametype; uint16_t flags; } s; @@ -114,6 +115,12 @@ struct hb_buffer_s int size; } plane[4]; // 3 Color components + alpha + struct qsv + { + void *qsv_atom; + void *filter_details; + } qsv_details; + #ifdef USE_OPENCL struct cl_data { @@ -412,6 +419,7 @@ enum WORK_ENCVOBSUB, WORK_RENDER, WORK_ENCAVCODEC, + WORK_ENCQSV, WORK_ENCX264, WORK_ENCTHEORA, WORK_DECA52, @@ -439,6 +447,12 @@ extern hb_filter_object_t hb_filter_crop_scale; extern hb_filter_object_t hb_filter_render_sub; extern hb_filter_object_t hb_filter_vfr; +#ifdef USE_QSV +extern hb_filter_object_t hb_filter_qsv; +extern hb_filter_object_t hb_filter_qsv_pre; +extern hb_filter_object_t hb_filter_qsv_post; +#endif + // Picture flags used by filters #ifndef PIC_FLAG_REPEAT_FIRST_FIELD #define PIC_FLAG_REPEAT_FIRST_FIELD 256 @@ -475,7 +489,9 @@ typedef struct hb_mux_data_s hb_mux_data_t; hb_mux_object_t * hb_mux_##a##_init( hb_job_t * ); DECLARE_MUX( mp4 ); -DECLARE_MUX( avi ); -DECLARE_MUX( ogm ); DECLARE_MUX( mkv ); +DECLARE_MUX( avformat ); +void hb_muxmp4_process_subtitle_style( uint8_t *input, + uint8_t *output, + uint8_t *style, uint16_t *stylesize ); diff --git a/libhb/lang.c b/libhb/lang.c index 2e0cc3a48..4600f1020 100644 --- a/libhb/lang.c +++ b/libhb/lang.c @@ -200,6 +200,8 @@ static const iso639_lang_t languages[] = { "Zulu", "", "zu", "zul" }, { NULL, NULL, NULL } }; +static const int lang_count = sizeof(languages) / sizeof(languages[0]); + iso639_lang_t * lang_for_code( int code ) { char code_string[2]; @@ -269,3 +271,18 @@ iso639_lang_t * lang_for_english( const char * english ) return (iso639_lang_t*) languages; } +const iso639_lang_t* lang_get_next(const iso639_lang_t *last) +{ + if (last == NULL) + { + return (const iso639_lang_t*)languages; + } + if (last < languages || // out of bounds + last >= languages + lang_count - 2) // last valid language + { + return NULL; + } + return ++last; +} + + diff --git a/libhb/lang.h b/libhb/lang.h index 9df8e10f4..cf4ecc321 100644 --- a/libhb/lang.h +++ b/libhb/lang.h @@ -33,6 +33,14 @@ iso639_lang_t * lang_for_code2( const char *code2 ); int lang_to_code(const iso639_lang_t *lang); iso639_lang_t * lang_for_english( const char * english ); + +/* + * Get the next language in the list. + * Returns NULL if there are no more languages. + * Pass NULL to get the first language in the list. + */ +const iso639_lang_t* lang_get_next(const iso639_lang_t *last); + #ifdef __cplusplus } #endif diff --git a/libhb/mcdeint.c b/libhb/mcdeint.c deleted file mode 100644 index 9eb6f5ac0..000000000 --- a/libhb/mcdeint.c +++ /dev/null @@ -1,221 +0,0 @@ -/* - Copyright (C) 2006 Michael Niedermayer <[email protected]> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include "hb.h" -#include "hbffmpeg.h" -#include "mpeg2dec/mpeg2.h" -#include "mcdeint.h" - -#define SUPPRESS_AV_LOG - -#define ABS(a) ((a) > 0 ? (a) : (-(a))) - -void mcdeint_init( mcdeint_private_t * pv, - int mode, - int qp, - int pix_fmt, - int width, - int height ) -{ - pv->mcdeint_mode = mode; - pv->mcdeint_qp = qp; - - /* Allocate mcdeint specific buffers */ - if( pv->mcdeint_mode >= 0 ) - { - avcodec_register_all(); - - AVCodec * enc = avcodec_find_encoder( AV_CODEC_ID_SNOW ); - - // Snow ME_ITER will crash if width & height are not 16 pixel - // aligned (or 8 pixel if CODEC_FLAG_4MV is set). - // Fortunately, our input buffers have padding - width = (width + 15) & ~0xf; - height = (height + 15) & ~0xf; - - AVCodecContext * avctx_enc; - - avctx_enc = pv->mcdeint_avctx_enc = avcodec_alloc_context3( enc ); - - avctx_enc->width = width; - avctx_enc->height = height; - avctx_enc->time_base = (AVRational){1,25}; // meaningless - avctx_enc->gop_size = 300; - avctx_enc->max_b_frames = 0; - avctx_enc->pix_fmt = pix_fmt; - avctx_enc->flags = CODEC_FLAG_QSCALE | CODEC_FLAG_LOW_DELAY; - avctx_enc->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL; - avctx_enc->global_quality = 1; - avctx_enc->me_cmp = FF_CMP_SAD; //SSE; - avctx_enc->me_sub_cmp = FF_CMP_SAD; //SSE; - avctx_enc->mb_cmp = FF_CMP_SSE; - - switch( pv->mcdeint_mode ) - { - case 3: - avctx_enc->refs = 3; - case 2: - avctx_enc->me_method = ME_ITER; - case 1: - avctx_enc->flags |= CODEC_FLAG_4MV; - avctx_enc->dia_size =2; - case 0: - avctx_enc->flags |= CODEC_FLAG_QPEL; - } - - hb_avcodec_open(avctx_enc, enc, NULL, 0); - - pv->mcdeint_frame = avcodec_alloc_frame(); - av_new_packet( &pv->mcdeint_pkt, width * height * 10 ); - } -} - -void mcdeint_close( mcdeint_private_t * pv ) -{ - /* Cleanup mcdeint specific buffers */ - if( pv->mcdeint_mode >= 0 ) - { - if( pv->mcdeint_avctx_enc ) - { - hb_avcodec_close( pv->mcdeint_avctx_enc ); - av_freep( &pv->mcdeint_avctx_enc ); - } - av_free_packet( &pv->mcdeint_pkt ); - } -} - -void mcdeint_filter( hb_buffer_t * dst_buf, - hb_buffer_t * src_buf, - int parity, - mcdeint_private_t * pv ) -{ - int x, y, i; - -#ifdef SUPPRESS_AV_LOG - /* TODO: temporarily change log level to suppress obnoxious debug output */ - int loglevel = av_log_get_level(); - av_log_set_level( AV_LOG_QUIET ); -#endif - - for( i=0; i<3; i++ ) - { - pv->mcdeint_frame->data[i] = src_buf->plane[i].data; - pv->mcdeint_frame->linesize[i] = src_buf->plane[i].stride; - } - pv->mcdeint_avctx_enc->me_cmp = FF_CMP_SAD; - pv->mcdeint_avctx_enc->me_sub_cmp = FF_CMP_SAD; - pv->mcdeint_frame->quality = pv->mcdeint_qp * FF_QP2LAMBDA; - - int got_packet; - - avcodec_encode_video2( pv->mcdeint_avctx_enc, - &pv->mcdeint_pkt, pv->mcdeint_frame, &got_packet ); - - pv->mcdeint_frame_dec = pv->mcdeint_avctx_enc->coded_frame; - - for( i = 0; i < 3; i++ ) - { - uint8_t * dst = dst_buf->plane[i].data; - uint8_t * src = src_buf->plane[i].data; - int w = src_buf->plane[i].stride; - int h = src_buf->plane[i].height; - int fils = pv->mcdeint_frame_dec->linesize[i]; - int srcs = src_buf->plane[i].stride; - - for (y = parity; y < h; y += 2) - { - for( x = 0; x < w; x++ ) - { - if( (x-1)+(y-1)*w >= 0 && (x+1)+(y+1)*w < w*h ) - { - uint8_t * filp = - &pv->mcdeint_frame_dec->data[i][x + y * fils]; - uint8_t * srcp = &src[x + y * srcs]; - - int diff0 = filp[-fils] - srcp[-srcs]; - int diff1 = filp[+fils] - srcp[+srcs]; - int spatial_score; - - spatial_score = - ABS(srcp[-srcs-1] - srcp[+srcs-1]) + - ABS(srcp[-srcs ] - srcp[+srcs ]) + - ABS(srcp[-srcs+1] - srcp[+srcs+1]) - 1; - - int temp = filp[0]; - -#define MCDEINT_CHECK(j)\ - { int score = ABS(srcp[-srcs-1+j] - srcp[+srcs-1-j])\ - + ABS(srcp[-srcs +j] - srcp[+srcs -j])\ - + ABS(srcp[-srcs+1+j] - srcp[+srcs+1-j]);\ - if( score < spatial_score ) {\ - spatial_score = score;\ - diff0 = filp[-fils+j] - srcp[-srcs+j];\ - diff1 = filp[+fils-j] - srcp[+srcs-j]; - - if( x >= 2 && x <= w - 3 ) - { - MCDEINT_CHECK(-1) - if( x >= 3 && x <= w - 4 ) - { - MCDEINT_CHECK(-2) }} }} - } - } - if( x >= 2 && x <= w - 3 ) - { - MCDEINT_CHECK(1) - if( x >= 3 && x <= w - 4 ) - { - MCDEINT_CHECK(2) }} }} - } - } - - if(diff0 + diff1 > 0) - { - temp -= (diff0 + diff1 - - ABS( ABS(diff0) - ABS(diff1) ) / 2) / 2; - } - else - { - temp -= (diff0 + diff1 + - ABS( ABS(diff0) - ABS(diff1) ) / 2) / 2; - } - - filp[0] = dst[x + y*w] = - temp > 255U ? ~(temp>>31) : temp; - } - else - { - dst[x + y*w] = - pv->mcdeint_frame_dec->data[i][x + y*fils]; - } - } - } - - for( y = !parity; y < h; y += 2 ) - { - memcpy(&pv->mcdeint_frame_dec->data[i][y * fils], - &src[y * srcs], w); - memcpy(&dst[y * w], &src[y * srcs], w); - } - } - -#ifdef SUPPRESS_AV_LOG - /* TODO: restore previous log level */ - av_log_set_level(loglevel); -#endif -} diff --git a/libhb/mcdeint.h b/libhb/mcdeint.h deleted file mode 100644 index 621fd58e2..000000000 --- a/libhb/mcdeint.h +++ /dev/null @@ -1,35 +0,0 @@ -/* mcdeint.h - - 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 - */ - -struct mcdeint_private_s -{ - int mcdeint_mode; - int mcdeint_qp; - - AVPacket mcdeint_pkt; - AVCodecContext * mcdeint_avctx_enc; - AVFrame * mcdeint_frame; - AVFrame * mcdeint_frame_dec; -}; - -typedef struct mcdeint_private_s mcdeint_private_t; - -void mcdeint_init( mcdeint_private_t * pv, - int mode, - int qp, - int pix_fmt, - int width, - int height ); - -void mcdeint_close( mcdeint_private_t * pv ); - -void mcdeint_filter( hb_buffer_t * dst, - hb_buffer_t * src, - int parity, - mcdeint_private_t * pv ); diff --git a/libhb/module.defs b/libhb/module.defs index daa5396e2..e06c6331b 100644 --- a/libhb/module.defs +++ b/libhb/module.defs @@ -1,6 +1,6 @@ __deps__ := A52DEC BZIP2 FAAC FFMPEG FONTCONFIG FREETYPE LAME LIBASS LIBDCA \ LIBDVDREAD LIBDVDNAV LIBICONV LIBMKV LIBOGG LIBSAMPLERATE LIBTHEORA LIBVORBIS LIBXML2 \ - MP4V2 MPEG2DEC PTHREADW32 X264 ZLIB LIBBLURAY FDKAAC + MP4V2 MPEG2DEC PTHREADW32 X264 ZLIB LIBBLURAY FDKAAC LIBMFX $(eval $(call import.MODULE.defs,LIBHB,libhb,$(__deps__))) $(eval $(call import.GCC,LIBHB)) @@ -13,7 +13,12 @@ LIBHB.build/ = $(BUILD/)libhb/ LIBHB.m4.in = $(wildcard $(LIBHB.src/)*.m4) LIBHB.m4.out = $(patsubst $(LIBHB.src/)%.m4,$(LIBHB.build/)%,$(LIBHB.m4.in)) +ifeq (1,$(FEATURE.qsv)) LIBHB.c = $(wildcard $(LIBHB.src/)*.c) +else +LIBHB.c = $(filter-out $(wildcard $(LIBHB.src/)*qsv*.c), $(wildcard $(LIBHB.src/)*.c)) +endif + LIBHB.c.o = $(patsubst $(SRC/)%.c,$(BUILD/)%.o,$(LIBHB.c)) LIBHB.d = $(LIBHB.m4.out) $(LIBHB.h.out) \ $(foreach n,$(LIBHB.prerequisites),$($n.INSTALL.target) ) @@ -48,6 +53,21 @@ ifeq (1,$(FEATURE.hwd)) LIBHB.GCC.D += USE_HWD endif +ifeq (1,$(FEATURE.libav_aac)) +LIBHB.GCC.D += USE_LIBAV_AAC +endif +ifeq (1,$(FEATURE.faac)) +LIBHB.GCC.D += USE_FAAC +endif +ifeq (1,$(FEATURE.mp4v2)) +LIBHB.GCC.D += USE_MP4V2 +endif +ifeq (1,$(FEATURE.libmkv)) +LIBHB.GCC.D += USE_LIBMKV +endif +ifeq (1,$(FEATURE.avformat)) +LIBHB.GCC.D += USE_AVFORMAT +endif LIBHB.GCC.D += __LIBHB__ USE_PTHREAD LIBHB.GCC.I += $(LIBHB.build/) $(CONTRIB.build/)include @@ -67,11 +87,15 @@ else ifeq ($(BUILD.system),mingw) LIBHB.GCC.D += SYS_MINGW PTW32_STATIC_LIB LIBHB.GCC.args.extra.dylib++ += -Wl,--enable-auto-import -static else ifeq ($(BUILD.system),solaris) - LIBHB.GCC.D += SYS_SunOS _LARGEFILE_SOURCE _FILE_OFFSET_BITS=64 + LIBHB.GCC.D += SYS_SunOS _LARGEFILE_SOURCE _FILE_OFFSET_BITS=64 _POSIX_C_SOURCE=200112L __EXTENSIONS__ else LIBHB.platform.D = SYS_UNKNOWN endif +ifeq (1,$(FEATURE.qsv)) + LIBHB.GCC.D += USE_QSV HAVE_THREADS=1 +endif + ## required for <libdvdread/*.h> ifneq (,$(filter $(BUILD.arch),ppc ppc64)) LIBHB.GCC.D += WORDS_BIGENDIAN @@ -108,8 +132,8 @@ LIBHB.dll = $(LIBHB.build/)hb.dll LIBHB.lib = $(LIBHB.build/)hb.lib LIBHB.dll.libs = $(foreach n, \ - a52 ass avcodec avformat avutil avresample dvdnav dvdread faac \ - fontconfig freetype mkv mpeg2 mp3lame mp4v2 \ + a52 ass avcodec avformat avutil avresample dvdnav dvdread \ + fontconfig freetype mpeg2 mp3lame \ ogg samplerate swscale theora vorbis vorbisenc x264 xml2 bluray, \ $(CONTRIB.build/)lib/lib$(n).a ) @@ -117,6 +141,22 @@ ifeq (1,$(FEATURE.fdk_aac)) LIBHB.dll.libs += $(CONTRIB.build/)lib/libfdk-aac.a endif +ifeq (1,$(FEATURE.faac)) +LIBHB.dll.libs += $(CONTRIB.build/)lib/libfaac.a +endif + +ifeq (1,$(FEATURE.qsv)) +LIBHB.dll.libs += $(CONTRIB.build/)lib/libmfx.a +endif + +ifeq (1,$(FEATURE.mp4v2)) +LIBHB.dll.libs += $(CONTRIB.build/)lib/libmp4v2.a +endif + +ifeq (1,$(FEATURE.libmkv)) +LIBHB.dll.libs += $(CONTRIB.build/)lib/libmkv.a +endif + ifneq ($(HAS.iconv),1) LIBHB.dll.libs += $(CONTRIB.build/)lib/libiconv.a else diff --git a/libhb/muxavformat.c b/libhb/muxavformat.c new file mode 100644 index 000000000..31b9aa46a --- /dev/null +++ b/libhb/muxavformat.c @@ -0,0 +1,1250 @@ +/* muxavformat.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 + */ + +#if defined(USE_AVFORMAT) + +#include <ogg/ogg.h> +#include "libavformat/avformat.h" +#include "libavutil/avstring.h" +#include "libavutil/intreadwrite.h" + +#include "hb.h" +#include "lang.h" + +struct hb_mux_data_s +{ + enum + { + MUX_TYPE_VIDEO, + MUX_TYPE_AUDIO, + MUX_TYPE_SUBTITLE + } type; + + AVStream *st; + + int64_t duration; + + hb_buffer_t * delay_buf; + + int64_t prev_chapter_tc; + int16_t current_chapter; +}; + +struct hb_mux_object_s +{ + HB_MUX_COMMON; + + hb_job_t * job; + + AVFormatContext * oc; + AVRational time_base; + + int ntracks; + hb_mux_data_t ** tracks; + + int delay; +}; + +enum +{ + META_TITLE, + META_ARTIST, + META_DIRECTOR, + META_COMPOSER, + META_RELEASE_DATE, + META_COMMENT, + META_ALBUM, + META_GENRE, + META_DESCRIPTION, + META_SYNOPSIS, + META_LAST +}; + +enum +{ + META_MUX_MP4, + META_MUX_MKV, + META_MUX_LAST +}; + +const char *metadata_keys[META_LAST][META_MUX_LAST] = +{ + {"title", "TITLE"}, + {"artist", "ARTIST"}, + {"album_artist", "DIRECTOR"}, + {"composer", "COMPOSER"}, + {"date", "DATE_RELEASED"}, + {"comment", "SUMMARY"}, + {"album", NULL}, + {"genre", "GENRE"}, + {"description", "DESCRIPTION"}, + {"synopsis", "SYNOPSIS"} +}; + +static char* lookup_lang_code(int mux, char *iso639_2) +{ + iso639_lang_t *lang; + char *out = NULL; + + switch (mux) + { + case HB_MUX_AV_MP4: + out = iso639_2; + break; + case HB_MUX_AV_MKV: + // MKV lang codes should be ISO-639-2B if it exists, + // else ISO-639-2 + lang = lang_for_code2( iso639_2 ); + out = lang->iso639_2b ? lang->iso639_2b : lang->iso639_2; + break; + default: + break; + } + return out; +} + +/********************************************************************** + * avformatInit + ********************************************************************** + * Allocates hb_mux_data_t structures, create file and write headers + *********************************************************************/ +static int avformatInit( hb_mux_object_t * m ) +{ + hb_job_t * job = m->job; + hb_audio_t * audio; + hb_mux_data_t * track; + int meta_mux; + int max_tracks; + int ii, ret; + + const char *muxer_name = NULL; + + uint8_t default_track_flag = 1; + uint8_t need_fonts = 0; + char *lang; + + + m->delay = -1; + max_tracks = 1 + hb_list_count( job->list_audio ) + + hb_list_count( job->list_subtitle ); + + m->tracks = calloc(max_tracks, sizeof(hb_mux_data_t*)); + + m->oc = avformat_alloc_context(); + if (m->oc == NULL) + { + hb_error( "Could not initialize avformat context." ); + goto error; + } + + switch (job->mux) + { + case HB_MUX_AV_MP4: + m->time_base.num = 1; + m->time_base.den = 90000; + if( job->ipod_atom ) + muxer_name = "ipod"; + else + muxer_name = "mp4"; + meta_mux = META_MUX_MP4; + break; + + case HB_MUX_AV_MKV: + // libavformat is essentially hard coded such that it only + // works with a timebase of 1/1000 + m->time_base.num = 1; + m->time_base.den = 1000; + muxer_name = "matroska"; + meta_mux = META_MUX_MKV; + break; + + default: + { + hb_error("Invalid Mux %x", job->mux); + goto error; + } + } + m->oc->oformat = av_guess_format(muxer_name, NULL, NULL); + if(m->oc->oformat == NULL) + { + hb_error("Could not guess output format %s", muxer_name); + goto error; + } + av_strlcpy(m->oc->filename, job->file, sizeof(m->oc->filename)); + ret = avio_open2(&m->oc->pb, job->file, AVIO_FLAG_WRITE, + &m->oc->interrupt_callback, NULL); + if( ret < 0 ) + { + hb_error( "avio_open2 failed, errno %d", ret); + goto error; + } + + /* Video track */ + track = m->tracks[m->ntracks++] = calloc(1, sizeof( hb_mux_data_t ) ); + job->mux_data = track; + + track->type = MUX_TYPE_VIDEO; + track->st = avformat_new_stream(m->oc, NULL); + if (track->st == NULL) + { + hb_error("Could not initialize video stream"); + goto error; + } + track->st->time_base = m->time_base; + avcodec_get_context_defaults3(track->st->codec, NULL); + + track->st->codec->codec_type = AVMEDIA_TYPE_VIDEO; + track->st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; + + uint8_t *priv_data = NULL; + int priv_size = 0; + switch (job->vcodec) + { + case HB_VCODEC_X264: + case HB_VCODEC_QSV_H264: + track->st->codec->codec_id = AV_CODEC_ID_H264; + + /* Taken from x264 muxers.c */ + priv_size = 5 + 1 + 2 + job->config.h264.sps_length + 1 + 2 + + job->config.h264.pps_length; + priv_data = av_malloc(priv_size); + if (priv_data == NULL) + { + hb_error("malloc failure"); + goto error; + } + + priv_data[0] = 1; + priv_data[1] = job->config.h264.sps[1]; /* AVCProfileIndication */ + priv_data[2] = job->config.h264.sps[2]; /* profile_compat */ + priv_data[3] = job->config.h264.sps[3]; /* AVCLevelIndication */ + priv_data[4] = 0xff; // nalu size length is four bytes + priv_data[5] = 0xe1; // one sps + + priv_data[6] = job->config.h264.sps_length >> 8; + priv_data[7] = job->config.h264.sps_length; + + memcpy(priv_data+8, job->config.h264.sps, + job->config.h264.sps_length); + + priv_data[8+job->config.h264.sps_length] = 1; // one pps + priv_data[9+job->config.h264.sps_length] = + job->config.h264.pps_length >> 8; + priv_data[10+job->config.h264.sps_length] = + job->config.h264.pps_length; + + memcpy(priv_data+11+job->config.h264.sps_length, + job->config.h264.pps, job->config.h264.pps_length ); + break; + + case HB_VCODEC_FFMPEG_MPEG4: + track->st->codec->codec_id = AV_CODEC_ID_MPEG4; + + if (job->config.mpeg4.length != 0) + { + priv_size = job->config.mpeg4.length; + priv_data = av_malloc(priv_size); + if (priv_data == NULL) + { + hb_error("malloc failure"); + goto error; + } + memcpy(priv_data, job->config.mpeg4.bytes, priv_size); + } + break; + + case HB_VCODEC_FFMPEG_MPEG2: + track->st->codec->codec_id = AV_CODEC_ID_MPEG2VIDEO; + + if (job->config.mpeg4.length != 0) + { + priv_size = job->config.mpeg4.length; + priv_data = av_malloc(priv_size); + if (priv_data == NULL) + { + hb_error("malloc failure"); + goto error; + } + memcpy(priv_data, job->config.mpeg4.bytes, priv_size); + } + break; + + case HB_VCODEC_THEORA: + { + track->st->codec->codec_id = AV_CODEC_ID_THEORA; + + int size = 0; + ogg_packet *ogg_headers[3]; + + for (ii = 0; ii < 3; ii++) + { + ogg_headers[ii] = (ogg_packet *)job->config.theora.headers[ii]; + size += ogg_headers[ii]->bytes + 2; + } + + priv_size = size; + priv_data = av_malloc(priv_size); + if (priv_data == NULL) + { + hb_error("malloc failure"); + goto error; + } + + size = 0; + for(ii = 0; ii < 3; ii++) + { + AV_WB16(priv_data + size, ogg_headers[ii]->bytes); + size += 2; + memcpy(priv_data+size, ogg_headers[ii]->packet, + ogg_headers[ii]->bytes); + size += ogg_headers[ii]->bytes; + } + } break; + + default: + hb_error("muxavformat: Unknown video codec: %x", job->vcodec); + goto error; + } + track->st->codec->extradata = priv_data; + track->st->codec->extradata_size = priv_size; + + if (job->anamorphic.mode > 0) + { + track->st->sample_aspect_ratio.num = job->anamorphic.par_width; + track->st->sample_aspect_ratio.den = job->anamorphic.par_height; + track->st->codec->sample_aspect_ratio.num = job->anamorphic.par_width; + track->st->codec->sample_aspect_ratio.den = job->anamorphic.par_height; + } + else + { + track->st->sample_aspect_ratio.num = 1; + track->st->sample_aspect_ratio.den = 1; + track->st->codec->sample_aspect_ratio.num = 1; + track->st->codec->sample_aspect_ratio.den = 1; + } + track->st->codec->width = job->width; + track->st->codec->height = job->height; + track->st->disposition |= AV_DISPOSITION_DEFAULT; + + int vrate_base, vrate; + if( job->pass == 2 ) + { + hb_interjob_t * interjob = hb_interjob_get( job->h ); + vrate_base = interjob->vrate_base; + vrate = interjob->vrate; + } + else + { + vrate_base = job->vrate_base; + vrate = job->vrate; + } + + // If the vrate is 27000000, there's a good chance this is + // a standard rate that we have in our hb_video_rates table. + // Because of rounding errors and approximations made while + // measuring framerate, the actual value may not be exact. So + // we look for rates that are "close" and make an adjustment + // to fps.den. + if (vrate == 27000000) + { + const hb_rate_t *video_framerate = NULL; + while ((video_framerate = hb_video_framerate_get_next(video_framerate)) != NULL) + { + if (abs(vrate_base - video_framerate->rate) < 10) + { + vrate_base = video_framerate->rate; + break; + } + } + } + hb_reduce(&vrate_base, &vrate, vrate_base, vrate); + if (job->mux == HB_MUX_AV_MP4) + { + // libavformat mp4 muxer requires that the codec time_base have the + // same denominator as the stream time_base, it uses it for the + // mdhd timescale. + double scale = (double)track->st->time_base.den / vrate; + track->st->codec->time_base.den = track->st->time_base.den; + track->st->codec->time_base.num = vrate_base * scale; + } + else + { + track->st->codec->time_base.num = vrate_base; + track->st->codec->time_base.den = vrate; + } + + /* add the audio tracks */ + for(ii = 0; ii < hb_list_count( job->list_audio ); ii++ ) + { + audio = hb_list_item( job->list_audio, ii ); + track = m->tracks[m->ntracks++] = calloc(1, sizeof( hb_mux_data_t ) ); + audio->priv.mux_data = track; + + track->type = MUX_TYPE_AUDIO; + + track->st = avformat_new_stream(m->oc, NULL); + if (track->st == NULL) + { + hb_error("Could not initialize audio stream"); + goto error; + } + avcodec_get_context_defaults3(track->st->codec, NULL); + + track->st->codec->codec_type = AVMEDIA_TYPE_AUDIO; + track->st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; + if (job->mux == HB_MUX_AV_MP4) + { + track->st->codec->time_base.num = audio->config.out.samples_per_frame; + track->st->codec->time_base.den = audio->config.out.samplerate; + track->st->time_base.num = 1; + track->st->time_base.den = audio->config.out.samplerate; + } + else + { + track->st->codec->time_base = m->time_base; + } + + priv_data = NULL; + priv_size = 0; + switch (audio->config.out.codec & HB_ACODEC_MASK) + { + case HB_ACODEC_DCA: + case HB_ACODEC_DCA_HD: + track->st->codec->codec_id = AV_CODEC_ID_DTS; + break; + case HB_ACODEC_AC3: + track->st->codec->codec_id = AV_CODEC_ID_AC3; + break; + case HB_ACODEC_LAME: + case HB_ACODEC_MP3: + track->st->codec->codec_id = AV_CODEC_ID_MP3; + break; + case HB_ACODEC_VORBIS: + { + track->st->codec->codec_id = AV_CODEC_ID_VORBIS; + + int jj, size = 0; + ogg_packet *ogg_headers[3]; + + for (jj = 0; jj < 3; jj++) + { + ogg_headers[jj] = (ogg_packet *)audio->priv.config.vorbis.headers[jj]; + size += ogg_headers[jj]->bytes + 2; + } + + priv_size = size; + priv_data = av_malloc(priv_size); + if (priv_data == NULL) + { + hb_error("malloc failure"); + goto error; + } + + size = 0; + for(jj = 0; jj < 3; jj++) + { + AV_WB16(priv_data + size, ogg_headers[jj]->bytes); + size += 2; + memcpy(priv_data+size, ogg_headers[jj]->packet, + ogg_headers[jj]->bytes); + size += ogg_headers[jj]->bytes; + } + } break; + case HB_ACODEC_FFFLAC: + case HB_ACODEC_FFFLAC24: + track->st->codec->codec_id = AV_CODEC_ID_FLAC; + + if (audio->priv.config.extradata.bytes) + { + priv_size = audio->priv.config.extradata.length; + priv_data = av_malloc(priv_size); + if (priv_data == NULL) + { + hb_error("malloc failure"); + goto error; + } + memcpy(priv_data, + audio->priv.config.extradata.bytes, + audio->priv.config.extradata.length); + } + break; + case HB_ACODEC_FAAC: + case HB_ACODEC_FFAAC: + case HB_ACODEC_CA_AAC: + case HB_ACODEC_CA_HAAC: + case HB_ACODEC_FDK_AAC: + case HB_ACODEC_FDK_HAAC: + track->st->codec->codec_id = AV_CODEC_ID_AAC; + + if (audio->priv.config.extradata.bytes) + { + priv_size = audio->priv.config.extradata.length; + priv_data = av_malloc(priv_size); + if (priv_data == NULL) + { + hb_error("malloc failure"); + goto error; + } + memcpy(priv_data, + audio->priv.config.extradata.bytes, + audio->priv.config.extradata.length); + } + break; + default: + hb_error("muxavformat: Unknown audio codec: %x", + audio->config.out.codec); + goto error; + } + track->st->codec->extradata = priv_data; + track->st->codec->extradata_size = priv_size; + + if( default_track_flag ) + { + track->st->disposition |= AV_DISPOSITION_DEFAULT; + default_track_flag = 0; + } + + lang = lookup_lang_code(job->mux, audio->config.lang.iso639_2 ); + if (lang != NULL) + { + av_dict_set(&track->st->metadata, "language", lang, 0); + } + track->st->codec->sample_rate = audio->config.out.samplerate; + if (audio->config.out.codec & HB_ACODEC_PASS_FLAG) + { + track->st->codec->channels = av_get_channel_layout_nb_channels(audio->config.in.channel_layout); + track->st->codec->channel_layout = audio->config.in.channel_layout; + } + else + { + track->st->codec->channels = hb_mixdown_get_discrete_channel_count(audio->config.out.mixdown); + track->st->codec->channel_layout = hb_ff_mixdown_xlat(audio->config.out.mixdown, NULL); + } + + char *name; + if (audio->config.out.name == NULL) + { + switch (track->st->codec->channels) + { + case 1: + name = "Mono"; + break; + + case 2: + name = "Stereo"; + break; + + default: + name = "Surround"; + break; + } + } + else + { + name = audio->config.out.name; + } + av_dict_set(&track->st->metadata, "title", name, 0); + } + + char * subidx_fmt = + "size: %dx%d\n" + "org: %d, %d\n" + "scale: 100%%, 100%%\n" + "alpha: 100%%\n" + "smooth: OFF\n" + "fadein/out: 50, 50\n" + "align: OFF at LEFT TOP\n" + "time offset: 0\n" + "forced subs: %s\n" + "palette: %06x, %06x, %06x, %06x, %06x, %06x, " + "%06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x, %06x\n" + "custom colors: OFF, tridx: 0000, " + "colors: 000000, 000000, 000000, 000000\n"; + + int subtitle_default = -1; + for( ii = 0; ii < hb_list_count( job->list_subtitle ); ii++ ) + { + hb_subtitle_t *subtitle = hb_list_item( job->list_subtitle, ii ); + + if( subtitle->config.dest == PASSTHRUSUB ) + { + if ( subtitle->config.default_track ) + subtitle_default = ii; + } + } + // Quicktime requires that at least one subtitle is enabled, + // else it doesn't show any of the subtitles. + // So check to see if any of the subtitles are flagged to be + // the defualt. The default will the the enabled track, else + // enable the first track. + if (job->mux == HB_MUX_AV_MP4 && subtitle_default == -1) + { + subtitle_default = 0; + } + + for( ii = 0; ii < hb_list_count( job->list_subtitle ); ii++ ) + { + hb_subtitle_t * subtitle; + uint32_t rgb[16]; + char subidx[2048]; + int len; + + subtitle = hb_list_item( job->list_subtitle, ii ); + if (subtitle->config.dest != PASSTHRUSUB) + continue; + + track = m->tracks[m->ntracks++] = calloc(1, sizeof( hb_mux_data_t ) ); + subtitle->mux_data = track; + + track->type = MUX_TYPE_SUBTITLE; + track->st = avformat_new_stream(m->oc, NULL); + if (track->st == NULL) + { + hb_error("Could not initialize subtitle stream"); + goto error; + } + avcodec_get_context_defaults3(track->st->codec, NULL); + + track->st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; + track->st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; + track->st->time_base = m->time_base; + track->st->codec->time_base = m->time_base; + track->st->codec->width = subtitle->width; + track->st->codec->height = subtitle->height; + + priv_data = NULL; + priv_size = 0; + switch (subtitle->source) + { + case VOBSUB: + { + int jj; + track->st->codec->codec_id = AV_CODEC_ID_DVD_SUBTITLE; + + for (jj = 0; jj < 16; jj++) + rgb[jj] = hb_yuv2rgb(subtitle->palette[jj]); + len = snprintf(subidx, 2048, subidx_fmt, + subtitle->width, subtitle->height, + 0, 0, "OFF", + rgb[0], rgb[1], rgb[2], rgb[3], + rgb[4], rgb[5], rgb[6], rgb[7], + rgb[8], rgb[9], rgb[10], rgb[11], + rgb[12], rgb[13], rgb[14], rgb[15]); + + priv_size = len + 1; + priv_data = av_malloc(priv_size); + if (priv_data == NULL) + { + hb_error("malloc failure"); + goto error; + } + memcpy(priv_data, subidx, priv_size); + } break; + + case PGSSUB: + { + track->st->codec->codec_id = AV_CODEC_ID_HDMV_PGS_SUBTITLE; + } break; + + case SSASUB: + { + if (job->mux == HB_MUX_AV_MP4) + { + track->st->codec->codec_id = AV_CODEC_ID_MOV_TEXT; + } + else + { + track->st->codec->codec_id = AV_CODEC_ID_SSA; + need_fonts = 1; + + if (subtitle->extradata_size) + { + priv_size = subtitle->extradata_size; + priv_data = av_malloc(priv_size); + if (priv_data == NULL) + { + hb_error("malloc failure"); + goto error; + } + memcpy(priv_data, subtitle->extradata, priv_size); + } + } + } break; + + case CC608SUB: + case CC708SUB: + case UTF8SUB: + case TX3GSUB: + case SRTSUB: + { + if (job->mux == HB_MUX_AV_MP4) + track->st->codec->codec_id = AV_CODEC_ID_MOV_TEXT; + else + track->st->codec->codec_id = AV_CODEC_ID_TEXT; + } break; + + default: + continue; + } + if (track->st->codec->codec_id == AV_CODEC_ID_MOV_TEXT) + { + // Build codec extradata for tx3g. + // If we were using a libav codec to generate this data + // this would (or should) be done for us. + uint8_t properties[] = { + 0x00, 0x00, 0x00, 0x00, // Display Flags + 0x01, // Horiz. Justification + 0xff, // Vert. Justification + 0x00, 0x00, 0x00, 0xff, // Bg color + 0x00, 0x00, 0x00, 0x00, // Default text box + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // Reserved + 0x00, 0x01, // Font ID + 0x00, // Font face + 0x18, // Font size + 0xff, 0xff, 0xff, 0xff, // Fg color + // Font table: + 0x00, 0x00, 0x00, 0x12, // Font table size + 'f','t','a','b', // Tag + 0x00, 0x01, // Count + 0x00, 0x01, // Font ID + 0x05, // Font name length + 'A','r','i','a','l' // Font name + }; + + int width, height = 60; + if (job->anamorphic.mode) + width = job->width * ((float)job->anamorphic.par_width / job->anamorphic.par_height); + else + width = job->width; + track->st->codec->width = width; + track->st->codec->height = height; + properties[14] = height >> 8; + properties[15] = height & 0xff; + properties[16] = width >> 8; + properties[17] = width & 0xff; + + priv_size = sizeof(properties); + priv_data = av_malloc(priv_size); + if (priv_data == NULL) + { + hb_error("malloc failure"); + goto error; + } + memcpy(priv_data, properties, priv_size); + } + track->st->codec->extradata = priv_data; + track->st->codec->extradata_size = priv_size; + + if ( ii == subtitle_default ) + { + track->st->disposition |= AV_DISPOSITION_DEFAULT; + } + + lang = lookup_lang_code(job->mux, subtitle->iso639_2 ); + if (lang != NULL) + { + av_dict_set(&track->st->metadata, "language", lang, 0); + } + } + + if (need_fonts) + { + hb_list_t * list_attachment = job->list_attachment; + int i; + for ( i = 0; i < hb_list_count(list_attachment); i++ ) + { + hb_attachment_t * attachment = hb_list_item( list_attachment, i ); + + if (attachment->type == FONT_TTF_ATTACH && + attachment->size > 0) + { + AVStream *st = avformat_new_stream(m->oc, NULL); + if (st == NULL) + { + hb_error("Could not initialize attachment stream"); + goto error; + } + avcodec_get_context_defaults3(st->codec, NULL); + + st->codec->codec_type = AVMEDIA_TYPE_ATTACHMENT; + track->st->codec->codec_id = AV_CODEC_ID_TTF; + + priv_size = attachment->size; + priv_data = av_malloc(priv_size); + if (priv_data == NULL) + { + hb_error("malloc failure"); + goto error; + } + memcpy(priv_data, attachment->data, priv_size); + + track->st->codec->extradata = priv_data; + track->st->codec->extradata_size = priv_size; + + av_dict_set(&st->metadata, "filename", attachment->name, 0); + } + } + } + + if( job->metadata ) + { + hb_metadata_t *md = job->metadata; + + hb_deep_log(2, "Writing Metadata to output file..."); + if (md->name && + metadata_keys[META_TITLE][meta_mux] != NULL) + { + av_dict_set(&m->oc->metadata, + metadata_keys[META_TITLE][meta_mux], md->name, 0); + } + if (md->artist && + metadata_keys[META_ARTIST][meta_mux] != NULL) + { + av_dict_set(&m->oc->metadata, + metadata_keys[META_ARTIST][meta_mux], md->artist, 0); + } + if (md->album_artist && + metadata_keys[META_DIRECTOR][meta_mux] != NULL) + { + av_dict_set(&m->oc->metadata, + metadata_keys[META_DIRECTOR][meta_mux], + md->album_artist, 0); + } + if (md->composer && + metadata_keys[META_COMPOSER][meta_mux] != NULL) + { + av_dict_set(&m->oc->metadata, + metadata_keys[META_COMPOSER][meta_mux], + md->composer, 0); + } + if (md->release_date && + metadata_keys[META_RELEASE_DATE][meta_mux] != NULL) + { + av_dict_set(&m->oc->metadata, + metadata_keys[META_RELEASE_DATE][meta_mux], + md->release_date, 0); + } + if (md->comment && + metadata_keys[META_COMMENT][meta_mux] != NULL) + { + av_dict_set(&m->oc->metadata, + metadata_keys[META_COMMENT][meta_mux], md->comment, 0); + } + if (!md->name && md->album && + metadata_keys[META_ALBUM][meta_mux] != NULL) + { + av_dict_set(&m->oc->metadata, + metadata_keys[META_ALBUM][meta_mux], md->album, 0); + } + if (md->genre && + metadata_keys[META_GENRE][meta_mux] != NULL) + { + av_dict_set(&m->oc->metadata, + metadata_keys[META_GENRE][meta_mux], md->genre, 0); + } + if (md->description && + metadata_keys[META_DESCRIPTION][meta_mux] != NULL) + { + av_dict_set(&m->oc->metadata, + metadata_keys[META_DESCRIPTION][meta_mux], + md->description, 0); + } + if (md->long_description && + metadata_keys[META_SYNOPSIS][meta_mux] != NULL) + { + av_dict_set(&m->oc->metadata, + metadata_keys[META_SYNOPSIS][meta_mux], + md->long_description, 0); + } + } + + AVDictionary * av_opts = NULL; + if (job->mp4_optimize && (job->mux & HB_MUX_MASK_MP4)) + av_dict_set( &av_opts, "movflags", "faststart", 0 ); + + ret = avformat_write_header(m->oc, &av_opts); + if( ret < 0 ) + { + av_dict_free( &av_opts ); + hb_error( "muxavformat: avformat_write_header failed!"); + goto error; + } + + AVDictionaryEntry *t = NULL; + while( ( t = av_dict_get( av_opts, "", t, AV_DICT_IGNORE_SUFFIX ) ) ) + { + hb_log( "muxavformat: Unknown option %s", t->key ); + } + av_dict_free( &av_opts ); + + return 0; + +error: + free(job->mux_data); + job->mux_data = NULL; + avformat_free_context(m->oc); + *job->die = 1; + return -1; +} + +static int add_chapter(hb_mux_object_t *m, int64_t start, int64_t end, char * title) +{ + AVChapter *chap; + AVChapter **chapters; + int nchap = m->oc->nb_chapters; + + nchap++; + chapters = av_realloc(m->oc->chapters, nchap * sizeof(AVChapter*)); + if (chapters == NULL) + { + hb_error("malloc failure"); + return -1; + } + + chap = av_mallocz(sizeof(AVChapter)); + if (chap == NULL) + { + hb_error("malloc failure"); + return -1; + } + + m->oc->chapters = chapters; + m->oc->chapters[nchap-1] = chap; + m->oc->nb_chapters = nchap; + + chap->id = nchap; + chap->time_base = m->time_base; + chap->start = start; + chap->end = end; + av_dict_set(&chap->metadata, "title", title, 0); + + return 0; +} + +// Video with b-frames and certain audio types require a lead-in delay. +// Compute the max delay and offset all timestamps by this amount. +// +// For mp4, avformat will automatically put entries in the edts atom +// to account for the offset of the first dts in each track. +static void computeDelay(hb_mux_object_t *m) +{ + int ii; + hb_audio_t * audio; + + m->delay = m->job->config.h264.init_delay; + for(ii = 0; ii < hb_list_count( m->job->list_audio ); ii++ ) + { + audio = hb_list_item( m->job->list_audio, ii ); + if (audio->config.out.delay > m->delay) + m->delay = audio->config.out.delay; + } +} + +static int avformatMux(hb_mux_object_t *m, hb_mux_data_t *track, hb_buffer_t *buf) +{ + AVPacket pkt; + int64_t dts, pts, duration = -1; + hb_job_t *job = m->job; + uint8_t tx3g_out[2048]; + + if (m->delay == -1) + { + computeDelay(m); + } + + if (buf != NULL) + { + if (buf->s.start != -1) + buf->s.start += m->delay; + if (buf->s.renderOffset != -1) + buf->s.renderOffset += m->delay; + } + + // We only compute dts duration for MP4 files + if (track->type == MUX_TYPE_VIDEO && (job->mux & HB_MUX_MASK_MP4)) + { + hb_buffer_t * tmp; + + // delay by one frame so that we can compute duration properly. + tmp = track->delay_buf; + track->delay_buf = buf; + buf = tmp; + } + if (buf == NULL) + return 0; + + if (buf->s.renderOffset == -1) + { + dts = av_rescale_q(buf->s.start, (AVRational){1,90000}, + track->st->time_base); + } + else + { + dts = av_rescale_q(buf->s.renderOffset, (AVRational){1,90000}, + track->st->time_base); + } + + pts = av_rescale_q(buf->s.start, (AVRational){1,90000}, + track->st->time_base); + + if (track->type == MUX_TYPE_VIDEO && track->delay_buf != NULL) + { + int64_t delayed_dts; + delayed_dts = av_rescale_q(track->delay_buf->s.renderOffset, + (AVRational){1,90000}, + track->st->time_base); + duration = delayed_dts - dts; + } + if (duration < 0 && buf->s.duration > 0) + { + duration = av_rescale_q(buf->s.duration, (AVRational){1,90000}, + track->st->time_base); + } + if (duration < 0) + { + // There is a possiblility that some subtitles get through the pipeline + // without ever discovering their true duration. Make the duration + // 10 seconds in this case. + if (track->type == MUX_TYPE_SUBTITLE) + duration = av_rescale_q(10, (AVRational){1,1}, + track->st->time_base); + else + duration = 0; + } + + av_init_packet(&pkt); + pkt.data = buf->data; + pkt.size = buf->size; + pkt.dts = dts; + pkt.pts = pts; + pkt.duration = duration; + + if (track->type == MUX_TYPE_VIDEO && ((job->vcodec & HB_VCODEC_H264_MASK) || + (job->vcodec & HB_VCODEC_FFMPEG_MASK))) + { + if (buf->s.frametype == HB_FRAME_IDR) + pkt.flags |= AV_PKT_FLAG_KEY; + } + else if (buf->s.frametype & HB_FRAME_KEY) + { + pkt.flags |= AV_PKT_FLAG_KEY; + } + + track->duration += pkt.duration; + + switch (track->type) + { + case MUX_TYPE_VIDEO: + { + if (job->chapter_markers && buf->s.new_chap) + { + hb_chapter_t *chapter; + + // reached chapter N, write marker for chapter N-1 + // we don't know the end time of chapter N-1 till we receive + // chapter N. So we are always writing the previous chapter + // mark. + track->current_chapter = buf->s.new_chap - 1; + + // chapter numbers start at 1, but the list starts at 0 + chapter = hb_list_item(job->list_chapter, + track->current_chapter - 1); + + // make sure we're not writing a chapter that has 0 length + if (chapter != NULL && track->prev_chapter_tc < pkt.pts) + { + char title[1024]; + if (chapter->title != NULL) + { + snprintf(title, 1023, "%s", chapter->title); + } + else + { + snprintf(title, 1023, "Chapter %d", + track->current_chapter); + } + add_chapter(m, track->prev_chapter_tc, pkt.pts, title); + } + track->prev_chapter_tc = pkt.pts; + } + } break; + + case MUX_TYPE_SUBTITLE: + { + if (job->mux == HB_MUX_AV_MP4) + { + /* Write an empty sample */ + if ( track->duration < pts ) + { + AVPacket empty_pkt; + uint8_t empty[2] = {0,0}; + + av_init_packet(&empty_pkt); + empty_pkt.data = empty; + empty_pkt.size = 2; + empty_pkt.dts = track->duration; + empty_pkt.pts = track->duration; + empty_pkt.duration = pts - duration; + empty_pkt.convergence_duration = empty_pkt.duration; + empty_pkt.stream_index = track->st->index; + int ret = av_interleaved_write_frame(m->oc, &empty_pkt); + if (ret < 0) + { + hb_error("av_interleaved_write_frame failed!"); + *job->die = 1; + return -1; + } + track->duration = pts; + } + uint8_t styleatom[2048];; + uint16_t stylesize = 0; + uint8_t buffer[2048]; + uint16_t buffersize = 0; + + *buffer = '\0'; + + /* + * Copy the subtitle into buffer stripping markup and creating + * style atoms for them. + */ + hb_muxmp4_process_subtitle_style( buf->data, + buffer, + styleatom, &stylesize ); + + buffersize = strlen((char*)buffer); + + /* Write the subtitle sample */ + memcpy( tx3g_out + 2, buffer, buffersize ); + memcpy( tx3g_out + 2 + buffersize, styleatom, stylesize); + tx3g_out[0] = ( buffersize >> 8 ) & 0xff; + tx3g_out[1] = buffersize & 0xff; + pkt.data = tx3g_out; + pkt.size = buffersize + stylesize + 2; + } + pkt.convergence_duration = pkt.duration; + + } break; + case MUX_TYPE_AUDIO: + default: + break; + } + + pkt.stream_index = track->st->index; + int ret = av_interleaved_write_frame(m->oc, &pkt); + if (ret < 0) + { + hb_error("av_interleaved_write_frame failed!"); + *job->die = 1; + return -1; + } + + hb_buffer_close( &buf ); + return 0; +} + +static int avformatEnd(hb_mux_object_t *m) +{ + hb_job_t *job = m->job; + hb_mux_data_t *track = job->mux_data; + + if( !job->mux_data ) + { + /* + * We must have failed to create the file in the first place. + */ + return 0; + } + + // Flush any delayed frames + int ii; + for (ii = 0; ii < m->ntracks; ii++) + { + avformatMux(m, m->tracks[ii], NULL); + } + + if (job->chapter_markers) + { + hb_chapter_t *chapter; + + // get the last chapter + chapter = hb_list_item(job->list_chapter, track->current_chapter++); + + // only write the last chapter marker if it lasts at least 1.5 second + if (chapter != NULL && chapter->duration > 135000LL) + { + char title[1024]; + if (chapter->title != NULL) + { + snprintf(title, 1023, "%s", chapter->title); + } + else + { + snprintf(title, 1023, "Chapter %d", track->current_chapter); + } + add_chapter(m, track->prev_chapter_tc, track->duration, title); + } + } + + // Update and track private data that can change during + // encode. + for(ii = 0; ii < hb_list_count( job->list_audio ); ii++) + { + AVStream *st; + hb_audio_t * audio; + + audio = hb_list_item(job->list_audio, ii); + st = audio->priv.mux_data->st; + + switch (audio->config.out.codec & HB_ACODEC_MASK) + { + case HB_ACODEC_FFFLAC: + case HB_ACODEC_FFFLAC24: + if( audio->priv.config.extradata.bytes ) + { + uint8_t *priv_data; + int priv_size; + + priv_size = audio->priv.config.extradata.length; + priv_data = av_realloc(st->codec->extradata, priv_size); + if (priv_data == NULL) + { + break; + } + memcpy(priv_data, + audio->priv.config.extradata.bytes, + audio->priv.config.extradata.length); + st->codec->extradata = priv_data; + st->codec->extradata_size = priv_size; + } + break; + default: + break; + } + } + + av_write_trailer(m->oc); + avio_close(m->oc->pb); + avformat_free_context(m->oc); + m->oc = NULL; + + return 0; +} + +hb_mux_object_t * hb_mux_avformat_init( hb_job_t * job ) +{ + hb_mux_object_t * m = calloc( sizeof( hb_mux_object_t ), 1 ); + m->init = avformatInit; + m->mux = avformatMux; + m->end = avformatEnd; + m->job = job; + return m; +} + +#endif // USE_AVFORMAT diff --git a/libhb/muxcommon.c b/libhb/muxcommon.c index a97ada699..9417c707b 100644 --- a/libhb/muxcommon.c +++ b/libhb/muxcommon.c @@ -459,12 +459,22 @@ hb_work_object_t * hb_muxer_init( hb_job_t * job ) { switch( job->mux ) { - case HB_MUX_MP4: +#ifdef USE_MP4V2 + case HB_MUX_MP4V2: mux->m = hb_mux_mp4_init( job ); break; - case HB_MUX_MKV: +#endif +#ifdef USE_LIBMKV + case HB_MUX_LIBMKV: mux->m = hb_mux_mkv_init( job ); break; +#endif +#ifdef USE_AVFORMAT + case HB_MUX_AV_MP4: + case HB_MUX_AV_MKV: + mux->m = hb_mux_avformat_init( job ); + break; +#endif default: hb_error( "No muxer selected, exiting" ); *job->die = 1; @@ -544,3 +554,245 @@ hb_work_object_t hb_muxer = muxClose }; +typedef struct stylerecord_s { + enum style_s {ITALIC, BOLD, UNDERLINE} style; + uint16_t start; + uint16_t stop; + struct stylerecord_s *next; +} stylerecord; + +static void hb_makestylerecord( stylerecord **stack, + enum style_s style, int start ) +{ + stylerecord *record = calloc( sizeof( stylerecord ), 1 ); + + if( record ) + { + record->style = style; + record->start = start; + record->next = *stack; + *stack = record; + } +} + +static void hb_makestyleatom( stylerecord *record, uint8_t *style) +{ + uint8_t face = 1; + hb_deep_log(3, "Made style '%s' from %d to %d", + record->style == ITALIC ? "Italic" : record->style == BOLD ? "Bold" : "Underline", record->start, record->stop); + + switch( record->style ) + { + case ITALIC: + face = 2; + break; + case BOLD: + face = 1; + break; + case UNDERLINE: + face = 4; + break; + default: + face = 2; + break; + } + + style[0] = (record->start >> 8) & 0xff; // startChar + style[1] = record->start & 0xff; + style[2] = (record->stop >> 8) & 0xff; // endChar + style[3] = record->stop & 0xff; + style[4] = (1 >> 8) & 0xff; // font-ID + style[5] = 1 & 0xff; + style[6] = face; // face-style-flags: 1 bold; 2 italic; 4 underline + style[7] = 24; // font-size + style[8] = 255; // r + style[9] = 255; // g + style[10] = 255; // b + style[11] = 255; // a +} + +/* + * Copy the input to output removing markup and adding markup to the style + * atom where appropriate. + */ +void hb_muxmp4_process_subtitle_style( uint8_t *input, + uint8_t *output, + uint8_t *style, uint16_t *stylesize ) +{ + uint8_t *reader = input; + uint8_t *writer = output; + uint8_t stylecount = 0; + uint16_t utf8_count = 0; // utf8 count from start of subtitle + stylerecord *stylestack = NULL; + stylerecord *oldrecord = NULL; + + while(*reader != '\0') { + if( ( *reader & 0xc0 ) == 0x80 ) + { + /* + * Track the utf8_count when doing markup so that we get the tx3g stops + * based on UTF8 chr counts rather than bytes. + */ + utf8_count++; + hb_deep_log( 3, "MuxMP4: Counted %d UTF-8 chrs within subtitle so far", + utf8_count); + } + if (*reader == '<') { + /* + * possible markup, peek at the next chr + */ + switch(*(reader+1)) { + case 'i': + if (*(reader+2) == '>') { + reader += 3; + hb_makestylerecord(&stylestack, ITALIC, (writer - output - utf8_count)); + } else { + *writer++ = *reader++; + } + break; + case 'b': + if (*(reader+2) == '>') { + reader += 3; + hb_makestylerecord(&stylestack, BOLD, (writer - output - utf8_count)); + } else { + *writer++ = *reader++; + } + break; + case 'u': + if (*(reader+2) == '>') { + reader += 3; + hb_makestylerecord(&stylestack, UNDERLINE, (writer - output - utf8_count)); + } else { + *writer++ = *reader++; + } + break; + case '/': + switch(*(reader+2)) { + case 'i': + if (*(reader+3) == '>') { + /* + * Check whether we then immediately start more markup of the same type, if so then + * lets not close it now and instead continue this markup. + */ + if ((*(reader+4) && *(reader+4) == '<') && + (*(reader+5) && *(reader+5) == 'i') && + (*(reader+6) && *(reader+6) == '>')) { + /* + * Opening italics right after, so don't close off these italics. + */ + hb_deep_log(3, "Joining two sets of italics"); + reader += (4 + 3); + continue; + } + + + if ((*(reader+4) && *(reader+4) == ' ') && + (*(reader+5) && *(reader+5) == '<') && + (*(reader+6) && *(reader+6) == 'i') && + (*(reader+7) && *(reader+7) == '>')) { + /* + * Opening italics right after, so don't close off these italics. + */ + hb_deep_log(3, "Joining two sets of italics (plus space)"); + reader += (4 + 4); + *writer++ = ' '; + continue; + } + if (stylestack && stylestack->style == ITALIC) { + uint8_t style_record[12]; + stylestack->stop = writer - output - utf8_count; + hb_makestyleatom(stylestack, style_record); + + memcpy(style + 10 + (12 * stylecount), style_record, 12); + stylecount++; + + oldrecord = stylestack; + stylestack = stylestack->next; + free(oldrecord); + } else { + hb_error("Mismatched Subtitle markup '%s'", input); + } + reader += 4; + } else { + *writer++ = *reader++; + } + break; + case 'b': + if (*(reader+3) == '>') { + if (stylestack && stylestack->style == BOLD) { + uint8_t style_record[12]; + stylestack->stop = writer - output - utf8_count; + hb_makestyleatom(stylestack, style_record); + + memcpy(style + 10 + (12 * stylecount), style_record, 12); + stylecount++; + oldrecord = stylestack; + stylestack = stylestack->next; + free(oldrecord); + } else { + hb_error("Mismatched Subtitle markup '%s'", input); + } + + reader += 4; + } else { + *writer++ = *reader++; + } + break; + case 'u': + if (*(reader+3) == '>') { + if (stylestack && stylestack->style == UNDERLINE) { + uint8_t style_record[12]; + stylestack->stop = writer - output - utf8_count; + hb_makestyleatom(stylestack, style_record); + + memcpy(style + 10 + (12 * stylecount), style_record, 12); + stylecount++; + + oldrecord = stylestack; + stylestack = stylestack->next; + free(oldrecord); + } else { + hb_error("Mismatched Subtitle markup '%s'", input); + } + reader += 4; + } else { + *writer++ = *reader++; + } + break; + default: + *writer++ = *reader++; + break; + } + break; + default: + *writer++ = *reader++; + break; + } + } else if (*reader == '\r') { + // skip '\r' and replace with '\n' if necessary + if (*(++reader) != '\n') { + *writer++ = '\n'; + } + } else { + *writer++ = *reader++; + } + } + *writer = '\0'; + + if( stylecount ) + { + *stylesize = 10 + ( stylecount * 12 ); + + memcpy( style + 4, "styl", 4); + + style[0] = 0; + style[1] = 0; + style[2] = (*stylesize >> 8) & 0xff; + style[3] = *stylesize & 0xff; + style[8] = (stylecount >> 8) & 0xff; + style[9] = stylecount & 0xff; + + } + +} + diff --git a/libhb/muxmkv.c b/libhb/muxmkv.c index a170eb557..f96a60e76 100644 --- a/libhb/muxmkv.c +++ b/libhb/muxmkv.c @@ -8,6 +8,9 @@ */ /* libmkv header */ + +#if defined(USE_LIBMKV) + #include "libmkv.h" #include <ogg/ogg.h> @@ -17,15 +20,16 @@ /* Scale factor to apply to timecodes to convert from HandBrake's * 1/90000s to nanoseconds as expected by libmkv */ -#define TIMECODE_SCALE 1000000000 / 90000 +#define NANOSECOND_SCALE 1000000000L +#define TIMECODE_SCALE 1000000000L / 90000 struct hb_mux_object_s { HB_MUX_COMMON; - hb_job_t * job; - + hb_job_t * job; mk_Writer * file; + int delay; }; struct hb_mux_data_s @@ -51,6 +55,49 @@ static uint8_t * create_flac_header( uint8_t *data, int size ) return out; } +static uint8_t* create_h264_header(hb_job_t *job, int *size) +{ + /* Taken from x264's muxers.c */ + int avcC_len = (5 + + 1 + 2 + job->config.h264.sps_length + + 1 + 2 + job->config.h264.pps_length); +#define MAX_AVCC_LEN 5 + 1 + 2 + 1024 + 1 + 2 + 1024 // FIXME + if (avcC_len > MAX_AVCC_LEN) + { + hb_log("create_h264_header: H.264 header too long (%d, max: %d)", + avcC_len, MAX_AVCC_LEN); + return NULL; + } + uint8_t *avcC = malloc(avcC_len); + if (avcC == NULL) + { + return NULL; + } + + avcC[0] = 1; + avcC[1] = job->config.h264.sps[1]; /* AVCProfileIndication */ + avcC[2] = job->config.h264.sps[2]; /* profile_compat */ + avcC[3] = job->config.h264.sps[3]; /* AVCLevelIndication */ + avcC[4] = 0xff; // nalu size length is four bytes + avcC[5] = 0xe1; // one sps + + avcC[6] = job->config.h264.sps_length >> 8; + avcC[7] = job->config.h264.sps_length; + memcpy(avcC + 8, job->config.h264.sps, job->config.h264.sps_length); + + avcC[8 + job->config.h264.sps_length] = 1; // one pps + avcC[9 + job->config.h264.sps_length] = job->config.h264.pps_length >> 8; + avcC[10 + job->config.h264.sps_length] = job->config.h264.pps_length; + memcpy(avcC + 11 + job->config.h264.sps_length, + job->config.h264.pps, job->config.h264.pps_length); + + if (size != NULL) + { + *size = avcC_len; + } + return avcC; +} + /********************************************************************** * MKVInit ********************************************************************** @@ -93,33 +140,15 @@ static int MKVInit( hb_mux_object_t * m ) switch (job->vcodec) { case HB_VCODEC_X264: - track->codecID = MK_VCODEC_MP4AVC; - /* Taken from x264 muxers.c */ - avcC_len = 5 + 1 + 2 + job->config.h264.sps_length + 1 + 2 + job->config.h264.pps_length; - avcC = malloc(avcC_len); - if (avcC == NULL) { + case HB_VCODEC_QSV_H264: + avcC = create_h264_header(job, &avcC_len); + if (avcC == NULL) + { free(track); return -1; } - - avcC[0] = 1; - avcC[1] = job->config.h264.sps[1]; /* AVCProfileIndication */ - avcC[2] = job->config.h264.sps[2]; /* profile_compat */ - avcC[3] = job->config.h264.sps[3]; /* AVCLevelIndication */ - avcC[4] = 0xff; // nalu size length is four bytes - avcC[5] = 0xe1; // one sps - - avcC[6] = job->config.h264.sps_length >> 8; - avcC[7] = job->config.h264.sps_length; - - memcpy(avcC+8, job->config.h264.sps, job->config.h264.sps_length); - - avcC[8+job->config.h264.sps_length] = 1; // one pps - avcC[9+job->config.h264.sps_length] = job->config.h264.pps_length >> 8; - avcC[10+job->config.h264.sps_length] = job->config.h264.pps_length; - - memcpy( avcC+11+job->config.h264.sps_length, job->config.h264.pps, job->config.h264.pps_length ); - track->codecPrivate = avcC; + track->codecID = MK_VCODEC_MP4AVC; + track->codecPrivate = avcC; track->codecPrivateSize = avcC_len; if (job->areBframes) track->minCache = 1; @@ -202,6 +231,9 @@ static int MKVInit( hb_mux_object_t * m ) mux_data = calloc(1, sizeof( hb_mux_data_t ) ); audio->priv.mux_data = mux_data; + if (audio->config.out.delay > m->delay) + m->delay = audio->config.out.delay; + mux_data->codec = audio->config.out.codec; memset(track, 0, sizeof(mk_TrackConfig)); @@ -440,14 +472,13 @@ static int MKVMux(hb_mux_object_t *m, hb_mux_data_t *mux_data, hb_buffer_t *buf) char chapter_name[1024]; hb_chapter_t *chapter_data; uint64_t timecode = 0; - ogg_packet *op = NULL; hb_job_t *job = m->job; + // Adjust for audio preroll and scale units + timecode = (buf->s.start + m->delay) * TIMECODE_SCALE; if (mux_data == job->mux_data) { /* Video */ - timecode = buf->s.start * TIMECODE_SCALE; - if (job->chapter_markers && buf->s.new_chap) { // reached chapter N, write marker for chapter N-1 @@ -475,22 +506,6 @@ static int MKVMux(hb_mux_object_t *m, hb_mux_data_t *mux_data, hb_buffer_t *buf) } 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, 0); - hb_buffer_close( &buf ); - return 0; - } } else if (mux_data->subtitle) { @@ -500,14 +515,13 @@ static int MKVMux(hb_mux_object_t *m, hb_mux_data_t *mux_data, hb_buffer_t *buf) *job->die = 1; } uint64_t duration; - timecode = buf->s.start * TIMECODE_SCALE; - if (buf->s.stop <= buf->s.start) + if (buf->s.duration < 0) { - duration = 0; + duration = 10 * NANOSECOND_SCALE; } else { - duration = buf->s.stop * TIMECODE_SCALE - timecode; + duration = buf->s.duration * TIMECODE_SCALE; } mk_addFrameData(m->file, mux_data->track, buf->data, buf->size); mk_setFrameFlags(m->file, mux_data->track, timecode, 1, duration); @@ -518,22 +532,6 @@ static int MKVMux(hb_mux_object_t *m, hb_mux_data_t *mux_data, hb_buffer_t *buf) else { /* Audio */ - timecode = buf->s.start * TIMECODE_SCALE; - if (mux_data->codec == HB_ACODEC_VORBIS) - { - /* ughhh, vorbis is a pain :( */ - op = (ogg_packet *)buf->data; - op->packet = buf->data + sizeof( ogg_packet ); - 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, 0); - hb_buffer_close( &buf ); - return 0; - } } if( mk_startFrame(m->file, mux_data->track) < 0) @@ -543,12 +541,12 @@ static int MKVMux(hb_mux_object_t *m, hb_mux_data_t *mux_data, hb_buffer_t *buf) } mk_addFrameData(m->file, mux_data->track, buf->data, buf->size); mk_setFrameFlags(m->file, mux_data->track, timecode, - (((job->vcodec == HB_VCODEC_X264 || - (job->vcodec & HB_VCODEC_FFMPEG_MASK)) && - mux_data == job->mux_data) ? - (buf->s.frametype == HB_FRAME_IDR) : - ((buf->s.frametype & HB_FRAME_KEY) != 0)), 0 ); - hb_buffer_close( &buf ); + ((mux_data == job->mux_data && + ((job->vcodec & HB_VCODEC_H264_MASK) || + (job->vcodec & HB_VCODEC_FFMPEG_MASK))) ? + (buf->s.frametype == HB_FRAME_IDR) : + (buf->s.frametype & HB_FRAME_KEY) != 0), 0); + hb_buffer_close(&buf); return 0; } @@ -690,3 +688,4 @@ hb_mux_object_t * hb_mux_mkv_init( hb_job_t * job ) m->job = job; return m; } +#endif // USE_LIBMKV diff --git a/libhb/muxmp4.c b/libhb/muxmp4.c index 66f02d5c7..bd706d29c 100644 --- a/libhb/muxmp4.c +++ b/libhb/muxmp4.c @@ -7,11 +7,13 @@ For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html */ +#include "hb.h" + +#if defined(USE_MP4V2) + #include "mp4v2/mp4v2.h" #include "a52dec/a52.h" -#include "hb.h" - struct hb_mux_object_s { HB_MUX_COMMON; @@ -94,7 +96,14 @@ static int MP4Init( hb_mux_object_t * m ) int subtitle_default; /* Flags for enabling/disabling tracks in an MP4. */ - typedef enum { TRACK_DISABLED = 0x0, TRACK_ENABLED = 0x1, TRACK_IN_MOVIE = 0x2, TRACK_IN_PREVIEW = 0x4, TRACK_IN_POSTER = 0x8} track_header_flags; + enum + { + TRACK_DISABLED = 0x0, + TRACK_ENABLED = 0x1, + TRACK_IN_MOVIE = 0x2, + TRACK_IN_PREVIEW = 0x4, + TRACK_IN_POSTER = 0x8 + }; /* Create an empty mp4 file */ if (job->largeFileSize) @@ -127,7 +136,7 @@ static int MP4Init( hb_mux_object_t * m ) return 0; } - if( job->vcodec == HB_VCODEC_X264 ) + if (job->vcodec & HB_VCODEC_H264_MASK) { /* Stolen from mp4creator */ MP4SetVideoProfileLevel( m->file, 0x7F ); @@ -658,262 +667,32 @@ static int MP4Init( hb_mux_object_t * m ) return 0; } -typedef struct stylerecord_s { - enum style_s {ITALIC, BOLD, UNDERLINE} style; - uint16_t start; - uint16_t stop; - struct stylerecord_s *next; -} stylerecord; - -static void hb_makestylerecord( stylerecord **stack, - enum style_s style, int start ) +static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, + hb_buffer_t * buf ) { - stylerecord *record = calloc( sizeof( stylerecord ), 1 ); - - if( record ) - { - record->style = style; - record->start = start; - record->next = *stack; - *stack = record; - } -} + hb_job_t * job = m->job; + int64_t duration, stop = -1; + int64_t offset = 0; + hb_buffer_t *tmp; -static void hb_makestyleatom( stylerecord *record, uint8_t *style) -{ - uint8_t face = 1; - hb_deep_log(3, "Made style '%s' from %d to %d", - record->style == ITALIC ? "Italic" : record->style == BOLD ? "Bold" : "Underline", record->start, record->stop); - - switch( record->style ) + if (buf != NULL) { - case ITALIC: - face = 2; - break; - case BOLD: - face = 1; - break; - case UNDERLINE: - face = 4; - break; - default: - face = 2; - break; - } - - style[0] = (record->start >> 8) & 0xff; // startChar - style[1] = record->start & 0xff; - style[2] = (record->stop >> 8) & 0xff; // endChar - style[3] = record->stop & 0xff; - style[4] = (1 >> 8) & 0xff; // font-ID - style[5] = 1 & 0xff; - style[6] = face; // face-style-flags: 1 bold; 2 italic; 4 underline - style[7] = 24; // font-size - style[8] = 255; // r - style[9] = 255; // g - style[10] = 255; // b - style[11] = 255; // a - -} - -/* - * Copy the input to output removing markup and adding markup to the style - * atom where appropriate. - */ -static void hb_muxmp4_process_subtitle_style( uint8_t *input, - uint8_t *output, - uint8_t *style, uint16_t *stylesize ) -{ - uint8_t *reader = input; - uint8_t *writer = output; - uint8_t stylecount = 0; - uint16_t utf8_count = 0; // utf8 count from start of subtitle - stylerecord *stylestack = NULL; - stylerecord *oldrecord = NULL; - - while(*reader != '\0') { - if( ( *reader & 0xc0 ) == 0x80 ) + if (buf->s.duration >= 0) { - /* - * Track the utf8_count when doing markup so that we get the tx3g stops - * based on UTF8 chr counts rather than bytes. - */ - utf8_count++; - hb_deep_log( 3, "MuxMP4: Counted %d UTF-8 chrs within subtitle so far", - utf8_count); + stop = buf->s.start + buf->s.duration; } - if (*reader == '<') { - /* - * possible markup, peek at the next chr - */ - switch(*(reader+1)) { - case 'i': - if (*(reader+2) == '>') { - reader += 3; - hb_makestylerecord(&stylestack, ITALIC, (writer - output - utf8_count)); - } else { - *writer++ = *reader++; - } - break; - case 'b': - if (*(reader+2) == '>') { - reader += 3; - hb_makestylerecord(&stylestack, BOLD, (writer - output - utf8_count)); - } else { - *writer++ = *reader++; - } - break; - case 'u': - if (*(reader+2) == '>') { - reader += 3; - hb_makestylerecord(&stylestack, UNDERLINE, (writer - output - utf8_count)); - } else { - *writer++ = *reader++; - } - break; - case '/': - switch(*(reader+2)) { - case 'i': - if (*(reader+3) == '>') { - /* - * Check whether we then immediately start more markup of the same type, if so then - * lets not close it now and instead continue this markup. - */ - if ((*(reader+4) && *(reader+4) == '<') && - (*(reader+5) && *(reader+5) == 'i') && - (*(reader+6) && *(reader+6) == '>')) { - /* - * Opening italics right after, so don't close off these italics. - */ - hb_deep_log(3, "Joining two sets of italics"); - reader += (4 + 3); - continue; - } - - - if ((*(reader+4) && *(reader+4) == ' ') && - (*(reader+5) && *(reader+5) == '<') && - (*(reader+6) && *(reader+6) == 'i') && - (*(reader+7) && *(reader+7) == '>')) { - /* - * Opening italics right after, so don't close off these italics. - */ - hb_deep_log(3, "Joining two sets of italics (plus space)"); - reader += (4 + 4); - *writer++ = ' '; - continue; - } - if (stylestack && stylestack->style == ITALIC) { - uint8_t style_record[12]; - stylestack->stop = writer - output - utf8_count; - hb_makestyleatom(stylestack, style_record); - - memcpy(style + 10 + (12 * stylecount), style_record, 12); - stylecount++; - - oldrecord = stylestack; - stylestack = stylestack->next; - free(oldrecord); - } else { - hb_error("Mismatched Subtitle markup '%s'", input); - } - reader += 4; - } else { - *writer++ = *reader++; - } - break; - case 'b': - if (*(reader+3) == '>') { - if (stylestack && stylestack->style == BOLD) { - uint8_t style_record[12]; - stylestack->stop = writer - output - utf8_count; - hb_makestyleatom(stylestack, style_record); - - memcpy(style + 10 + (12 * stylecount), style_record, 12); - stylecount++; - oldrecord = stylestack; - stylestack = stylestack->next; - free(oldrecord); - } else { - hb_error("Mismatched Subtitle markup '%s'", input); - } - - reader += 4; - } else { - *writer++ = *reader++; - } - break; - case 'u': - if (*(reader+3) == '>') { - if (stylestack && stylestack->style == UNDERLINE) { - uint8_t style_record[12]; - stylestack->stop = writer - output - utf8_count; - hb_makestyleatom(stylestack, style_record); - - memcpy(style + 10 + (12 * stylecount), style_record, 12); - stylecount++; - - oldrecord = stylestack; - stylestack = stylestack->next; - free(oldrecord); - } else { - hb_error("Mismatched Subtitle markup '%s'", input); - } - reader += 4; - } else { - *writer++ = *reader++; - } - break; - default: - *writer++ = *reader++; - break; - } - break; - default: - *writer++ = *reader++; - break; - } - } else if (*reader == '\r') { - // skip '\r' and replace with '\n' if necessary - if (*(++reader) != '\n') { - *writer++ = '\n'; - } - } else { - *writer++ = *reader++; + else if (mux_data->subtitle) + { + buf->s.duration = 10 * 90000; + stop = buf->s.start + buf->s.duration; } } - *writer = '\0'; - - if( stylecount ) - { - *stylesize = 10 + ( stylecount * 12 ); - - memcpy( style + 4, "styl", 4); - - style[0] = 0; - style[1] = 0; - style[2] = (*stylesize >> 8) & 0xff; - style[3] = *stylesize & 0xff; - style[8] = (stylecount >> 8) & 0xff; - style[9] = stylecount & 0xff; - - } - -} - -static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, - hb_buffer_t * buf ) -{ - hb_job_t * job = m->job; - int64_t duration; - int64_t offset = 0; - hb_buffer_t *tmp; if( mux_data == job->mux_data ) { /* Video */ - if( job->vcodec == HB_VCODEC_X264 || - ( job->vcodec & HB_VCODEC_FFMPEG_MASK ) ) + if ((job->vcodec & HB_VCODEC_H264_MASK) || + (job->vcodec & HB_VCODEC_FFMPEG_MASK)) { if ( buf && buf->s.start < buf->s.renderOffset ) { @@ -932,8 +711,10 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, if ( !buf ) return 0; - if( job->vcodec == HB_VCODEC_X264 || - ( job->vcodec & HB_VCODEC_FFMPEG_MASK ) ) + stop = buf->s.start + buf->s.duration; + + if ((job->vcodec & HB_VCODEC_H264_MASK) || + (job->vcodec & HB_VCODEC_FFMPEG_MASK)) { // x264 supplies us with DTS, so offset is PTS - DTS offset = buf->s.start - buf->s.renderOffset; @@ -970,8 +751,8 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, } } - if( job->vcodec == HB_VCODEC_X264 || - ( job->vcodec & HB_VCODEC_FFMPEG_MASK ) ) + if ((job->vcodec & HB_VCODEC_H264_MASK) || + (job->vcodec & HB_VCODEC_FFMPEG_MASK)) { // x264 supplies us with DTS if ( m->delay_buf ) @@ -980,7 +761,7 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, } else { - duration = buf->s.stop - m->sum_dur; + duration = stop - m->sum_dur; // Due to how libx264 generates DTS, it's possible for the // above calculation to be negative. // @@ -1016,7 +797,7 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, // We're getting the frames in decode order but the timestamps are // for presentation so we have to use durations and effectively // compute a DTS. - duration = buf->s.stop - buf->s.start; + duration = buf->s.duration; } if ( duration <= 0 ) @@ -1027,7 +808,7 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, try to fix the error so that the file will still be playable. */ hb_log("MP4Mux: illegal duration %"PRId64", start %"PRId64"," "stop %"PRId64", sum_dur %"PRId64, - duration, buf->s.start, buf->s.stop, m->sum_dur ); + duration, buf->s.start, stop, m->sum_dur ); /* we don't know when the next frame starts so we can't pick a valid duration for this one. we pick something "short" (roughly 1/3 of an NTSC frame time) to take time from @@ -1048,9 +829,8 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, } /* Here's where the sample actually gets muxed. */ - if( ( job->vcodec == HB_VCODEC_X264 || - ( job->vcodec & HB_VCODEC_FFMPEG_MASK ) ) - && mux_data == job->mux_data ) + if (mux_data == job->mux_data && ((job->vcodec & HB_VCODEC_H264_MASK) || + (job->vcodec & HB_VCODEC_FFMPEG_MASK))) { /* Compute dependency flags. * @@ -1111,11 +891,11 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, code should coalesce overlapping subtitle lines. */ if( buf->s.start < mux_data->sum_dur ) { - if ( buf->s.stop - mux_data->sum_dur > 90*500 ) + if ( stop - mux_data->sum_dur > 90*500 ) { hb_log("MP4Mux: shortening overlapping subtitle, " "start %"PRId64", stop %"PRId64", sum_dur %"PRId64, - buf->s.start, buf->s.stop, m->sum_dur); + buf->s.start, stop, m->sum_dur); buf->s.start = mux_data->sum_dur; } } @@ -1123,20 +903,10 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, { hb_log("MP4Mux: skipping overlapping subtitle, " "start %"PRId64", stop %"PRId64", sum_dur %"PRId64, - buf->s.start, buf->s.stop, m->sum_dur); + buf->s.start, stop, m->sum_dur); } else { - int64_t duration; - - if( buf->s.start < 0 ) - buf->s.start = mux_data->sum_dur; - - if( buf->s.stop < 0 ) - duration = 90000L * 10; - else - duration = buf->s.stop - buf->s.start; - /* Write an empty sample */ if ( mux_data->sum_dur < buf->s.start ) { @@ -1172,9 +942,9 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, buffersize = strlen((char*)buffer); - hb_deep_log(3, "MuxMP4:Sub:%fs:%"PRId64":%"PRId64":%"PRId64": %s", - (float)buf->s.start / 90000, buf->s.start, buf->s.stop, - duration, buffer); + hb_deep_log(3, "MuxMP4:Sub:%fs:%"PRId64":%"PRId64":%f: %s", + (float)buf->s.start / 90000, buf->s.start, stop, + buf->s.duration, buffer); /* Write the subtitle sample */ memcpy( output + 2, buffer, buffersize ); @@ -1186,7 +956,7 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, mux_data->track, output, buffersize + stylesize + 2, - duration, + buf->s.duration, 0, 1 )) { @@ -1194,21 +964,11 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, *job->die = 1; } - mux_data->sum_dur += duration; + mux_data->sum_dur += buf->s.duration; } } else if( mux_data->sub_format == PICTURESUB ) { - int64_t duration; - - if( buf->s.start < 0 ) - buf->s.start = mux_data->sum_dur; - - if( buf->s.stop < 0 ) - duration = 90000L * 10; - else - duration = buf->s.stop - buf->s.start; - /* Write an empty sample */ if ( mux_data->sum_dur < buf->s.start ) { @@ -1230,7 +990,7 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, mux_data->track, buf->data, buf->size, - duration, + buf->s.duration, 0, 1 )) { @@ -1238,7 +998,7 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, *job->die = 1; } - mux_data->sum_dur += duration; + mux_data->sum_dur += buf->s.duration; } } else @@ -1266,6 +1026,7 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, static int MP4End( hb_mux_object_t * m ) { hb_job_t * job = m->job; + int i; if (m->file != MP4_INVALID_FILE_HANDLE) { @@ -1295,19 +1056,32 @@ static int MP4End( hb_mux_object_t * m ) if ( job->config.h264.init_delay ) { - // Insert track edit to get A/V back in sync. The edit amount is - // the init_delay. - int64_t edit_amt = job->config.h264.init_delay; - MP4AddTrackEdit(m->file, 1, MP4_INVALID_EDIT_ID, edit_amt, - MP4GetTrackDuration(m->file, 1), 0); - if ( m->job->chapter_markers ) - { - // apply same edit to chapter track to keep it in sync with video - MP4AddTrackEdit(m->file, m->chapter_track, MP4_INVALID_EDIT_ID, - edit_amt, - MP4GetTrackDuration(m->file, m->chapter_track), 0); - } - } + // Insert track edit to get A/V back in sync. The edit amount is + // the init_delay. + int64_t edit_amt = job->config.h264.init_delay; + MP4AddTrackEdit(m->file, 1, MP4_INVALID_EDIT_ID, edit_amt, + MP4GetTrackDuration(m->file, 1), 0); + if ( m->job->chapter_markers ) + { + // apply same edit to chapter track to keep it in sync with video + MP4AddTrackEdit(m->file, m->chapter_track, MP4_INVALID_EDIT_ID, + edit_amt, + MP4GetTrackDuration(m->file, m->chapter_track), 0); + } + } + + // Check for audio preroll and add edit entries for audio + for( i = 0; i < hb_list_count( job->list_audio ); i++ ) + { + hb_audio_t *audio = hb_list_item( job->list_audio, i ); + hb_mux_data_t *mux_data = audio->priv.mux_data; + if (audio->config.out.delay > 0) + { + int64_t edit_amt = audio->config.out.delay; + MP4AddTrackEdit(m->file, mux_data->track, MP4_INVALID_EDIT_ID, + edit_amt, MP4GetTrackDuration(m->file, 1), 0); + } + } /* * Write the MP4 iTunes metadata if we have any metadata @@ -1413,3 +1187,4 @@ hb_mux_object_t * hb_mux_mp4_init( hb_job_t * job ) return m; } +#endif // USE_MP4V2 diff --git a/libhb/ports.c b/libhb/ports.c index 64b68bcb4..94bb95227 100644 --- a/libhb/ports.c +++ b/libhb/ports.c @@ -74,6 +74,7 @@ #include <unistd.h> #include "hb.h" +#include "libavutil/cpu.h" /************************************************************************ * hb_get_date() @@ -140,6 +141,27 @@ uint64_t hb_get_date() return( (uint64_t) tv.tv_sec * 1000 + (uint64_t) tv.tv_usec / 1000 ); } +uint64_t hb_get_time_us() +{ +#ifdef SYS_MINGW + static LARGE_INTEGER frequency; + LARGE_INTEGER cur_time; + + if (frequency.QuadPart == 0) + { + QueryPerformanceFrequency(&frequency); + } + + QueryPerformanceCounter(&cur_time); + + return (uint64_t)(1000000 * cur_time.QuadPart / frequency.QuadPart); +#else + struct timeval tv; + gettimeofday(&tv, NULL); + return ((uint64_t)tv.tv_sec * 1000000 + (uint64_t)tv.tv_usec); +#endif +} + /************************************************************************ * hb_snooze() ************************************************************************ @@ -161,21 +183,136 @@ void hb_snooze( int delay ) } /************************************************************************ - * hb_get_cpu_count() - ************************************************************************ - * Whenever possible, returns the number of CPUs on the current - * computer. Returns 1 otherwise. - * The detection is actually only performed on the first call. + * Get information about the CPU (number of cores, name, platform name) ************************************************************************/ +static void init_cpu_info(); +static int init_cpu_count(); +struct +{ + enum hb_cpu_platform platform; + const char *name; + char buf[48]; + int count; +} hb_cpu_info; + int hb_get_cpu_count() { - static int cpu_count = 0; + return hb_cpu_info.count; +} + +int hb_get_cpu_platform() +{ + return hb_cpu_info.platform; +} + +const char* hb_get_cpu_name() +{ + return hb_cpu_info.name; +} + +const char* hb_get_cpu_platform_name() +{ + switch (hb_cpu_info.platform) + { + // Intel 64 and IA-32 Architectures Software Developer's Manual, Vol. 3C + // Table 35-1: CPUID Signature Values of DisplayFamily_DisplayModel + case HB_CPU_PLATFORM_INTEL_SNB: + return "Intel microarchitecture Sandy Bridge"; + case HB_CPU_PLATFORM_INTEL_IVB: + return "Intel microarchitecture Ivy Bridge"; + case HB_CPU_PLATFORM_INTEL_HSW: + return "Intel microarchitecture Haswell"; + + default: + return NULL; + } +} + +static void init_cpu_info() +{ + hb_cpu_info.name = NULL; + hb_cpu_info.count = init_cpu_count(); + hb_cpu_info.platform = HB_CPU_PLATFORM_UNSPECIFIED; - if( cpu_count ) + if (av_get_cpu_flags() & AV_CPU_FLAG_SSE) { - return cpu_count; + int eax, ebx, ecx, edx, family, model; + + ff_cpu_cpuid(1, &eax, &ebx, &ecx, &edx); + family = ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff); + model = ((eax >> 4) & 0xf) + ((eax >> 12) & 0xf0); + + // Intel 64 and IA-32 Architectures Software Developer's Manual, Vol. 3C + // Table 35-1: CPUID Signature Values of DisplayFamily_DisplayModel + switch (family) + { + case 0x06: + { + switch (model) + { + case 0x2A: + case 0x2D: + hb_cpu_info.platform = HB_CPU_PLATFORM_INTEL_SNB; + break; + case 0x3A: + case 0x3E: + hb_cpu_info.platform = HB_CPU_PLATFORM_INTEL_IVB; + break; + case 0x3C: + case 0x45: + case 0x46: + hb_cpu_info.platform = HB_CPU_PLATFORM_INTEL_HSW; + break; + default: + break; + } + } break; + + default: + break; + } + + // Intel 64 and IA-32 Architectures Software Developer's Manual, Vol. 2A + // Figure 3-8: Determination of Support for the Processor Brand String + // Table 3-17: Information Returned by CPUID Instruction + ff_cpu_cpuid(0x80000000, &eax, &ebx, &ecx, &edx); + if ((eax & 0x80000004) < 0x80000004) + { + ff_cpu_cpuid(0x80000002, + (int*)&hb_cpu_info.buf[ 0], + (int*)&hb_cpu_info.buf[ 4], + (int*)&hb_cpu_info.buf[ 8], + (int*)&hb_cpu_info.buf[12]); + ff_cpu_cpuid(0x80000003, + (int*)&hb_cpu_info.buf[16], + (int*)&hb_cpu_info.buf[20], + (int*)&hb_cpu_info.buf[24], + (int*)&hb_cpu_info.buf[28]); + ff_cpu_cpuid(0x80000004, + (int*)&hb_cpu_info.buf[32], + (int*)&hb_cpu_info.buf[36], + (int*)&hb_cpu_info.buf[40], + (int*)&hb_cpu_info.buf[44]); + + hb_cpu_info.name = hb_cpu_info.buf; + hb_cpu_info.buf[47] = '\0'; // just in case + + while (isspace(*hb_cpu_info.name)) + { + // skip leading whitespace to prettify + hb_cpu_info.name++; + } + } } - cpu_count = 1; +} + +/* + * Whenever possible, returns the number of CPUs on the current computer. + * Returns 1 otherwise. + */ +static int init_cpu_count() +{ + int cpu_count = 1; #if defined(SYS_CYGWIN) || defined(SYS_MINGW) SYSTEM_INFO cpuinfo; @@ -263,6 +400,8 @@ int hb_platform_init() } #endif + init_cpu_info(); + return result; } diff --git a/libhb/ports.h b/libhb/ports.h index 10d01935b..a87b7ebd6 100644 --- a/libhb/ports.h +++ b/libhb/ports.h @@ -17,11 +17,31 @@ #endif /************************************************************************ + * CPU info utilities + ***********************************************************************/ +enum hb_cpu_platform +{ + // list of microarchitecture codenames + HB_CPU_PLATFORM_UNSPECIFIED = 0, + HB_CPU_PLATFORM_INTEL_SNB, + HB_CPU_PLATFORM_INTEL_IVB, + HB_CPU_PLATFORM_INTEL_HSW, +}; +int hb_get_cpu_count(); +int hb_get_cpu_platform(); +const char* hb_get_cpu_name(); +const char* hb_get_cpu_platform_name(); +extern void ff_cpu_cpuid(int index, int *eax, int *ebx, int *ecx, int *edx); + +/************************************************************************ * Utils ***********************************************************************/ +// provide time in ms uint64_t hb_get_date(); +// provide time in us +uint64_t hb_get_time_us(); + void hb_snooze( int delay ); -int hb_get_cpu_count(); int hb_platform_init(); #ifdef SYS_MINGW char *strtok_r(char *s, const char *delim, char **save_ptr); diff --git a/libhb/qsv_common.c b/libhb/qsv_common.c new file mode 100644 index 000000000..949176f0a --- /dev/null +++ b/libhb/qsv_common.c @@ -0,0 +1,860 @@ +/* qsv_common.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 + */ + +#include "hb.h" +#include "ports.h" +#include "common.h" +#include "hb_dict.h" +#include "qsv_common.h" +#include "h264_common.h" + +// for x264_vidformat_names etc. +#include "x264.h" + +// avoids a warning +#include "libavutil/cpu.h" +extern void ff_cpu_cpuid(int index, int *eax, int *ebx, int *ecx, int *edx); + +// make the Intel QSV information available to the UIs +hb_qsv_info_t *hb_qsv_info = NULL; + +// availability and versions +static mfxIMPL preferred_implementation; +static mfxVersion qsv_hardware_version; +static mfxVersion qsv_software_version; +static mfxVersion qsv_minimum_version; +static int qsv_hardware_available = 0; +static int qsv_software_available = 0; + +// check available Intel Media SDK version against a minimum +#define HB_CHECK_MFX_VERSION(MFX_VERSION, MAJOR, MINOR) \ + (MFX_VERSION.Major == MAJOR && MFX_VERSION.Minor >= MINOR) + +int hb_qsv_available() +{ + return hb_qsv_info != NULL && (qsv_hardware_available || + qsv_software_available); +} + +int hb_qsv_info_init() +{ + static int init_done = 0; + if (init_done) + return (hb_qsv_info == NULL); + init_done = 1; + + hb_qsv_info = calloc(1, sizeof(*hb_qsv_info)); + if (hb_qsv_info == NULL) + { + hb_error("hb_qsv_info_init: alloc failure"); + return -1; + } + + mfxSession session; + qsv_minimum_version.Major = HB_QSV_MINVERSION_MAJOR; + qsv_minimum_version.Minor = HB_QSV_MINVERSION_MINOR; + + // check for software fallback + if (MFXInit(MFX_IMPL_SOFTWARE, + &qsv_minimum_version, &session) == MFX_ERR_NONE) + { + qsv_software_available = 1; + preferred_implementation = MFX_IMPL_SOFTWARE; + // our minimum is supported, but query the actual version + MFXQueryVersion(session, &qsv_software_version); + MFXClose(session); + } + + // check for actual hardware support + if (MFXInit(MFX_IMPL_HARDWARE_ANY|MFX_IMPL_VIA_ANY, + &qsv_minimum_version, &session) == MFX_ERR_NONE) + { + qsv_hardware_available = 1; + preferred_implementation = MFX_IMPL_HARDWARE_ANY|MFX_IMPL_VIA_ANY; + // our minimum is supported, but query the actual version + MFXQueryVersion(session, &qsv_hardware_version); + MFXClose(session); + } + + // check for version-specific or hardware-specific capabilities + // we only use software as a fallback, so check hardware first + if (qsv_hardware_available) + { + if (HB_CHECK_MFX_VERSION(qsv_hardware_version, 1, 6)) + { + hb_qsv_info->capabilities |= HB_QSV_CAP_OPTION2_BRC; + hb_qsv_info->capabilities |= HB_QSV_CAP_MSDK_API_1_6; + } + if (hb_get_cpu_platform() == HB_CPU_PLATFORM_INTEL_HSW) + { + if (HB_CHECK_MFX_VERSION(qsv_hardware_version, 1, 7)) + { + hb_qsv_info->capabilities |= HB_QSV_CAP_OPTION2_TRELLIS; + hb_qsv_info->capabilities |= HB_QSV_CAP_OPTION2_LOOKAHEAD; + } + hb_qsv_info->capabilities |= HB_QSV_CAP_H264_BPYRAMID; + } + } + else if (qsv_software_available) + { + if (HB_CHECK_MFX_VERSION(qsv_software_version, 1, 6)) + { + hb_qsv_info->capabilities |= HB_QSV_CAP_MSDK_API_1_6; + hb_qsv_info->capabilities |= HB_QSV_CAP_H264_BPYRAMID; + } + } + + // note: we pass a pointer to MFXInit but it never gets modified + // let's make sure of it just to be safe though + if (qsv_minimum_version.Major != HB_QSV_MINVERSION_MAJOR || + qsv_minimum_version.Minor != HB_QSV_MINVERSION_MINOR) + { + hb_error("hb_qsv_info_init: minimum version (%d.%d) was modified", + qsv_minimum_version.Major, + qsv_minimum_version.Minor); + } + + // success + return 0; +} + +// we don't need it beyond this point +#undef HB_CHECK_MFX_VERSION + +void hb_qsv_info_print() +{ + if (hb_qsv_info == NULL) + { + hb_error("hb_qsv_info_print: QSV info not initialized!"); + } + + // is QSV available? + hb_log("Intel Quick Sync Video support: %s", + hb_qsv_available() ? "yes": "no"); + + // if we have Quick Sync Video support, also print the details + if (hb_qsv_available()) + { + if (qsv_hardware_available) + { + hb_log(" - Intel Media SDK hardware: API %d.%d (minimum: %d.%d)", + qsv_hardware_version.Major, + qsv_hardware_version.Minor, + qsv_minimum_version.Major, + qsv_minimum_version.Minor); + } + if (qsv_software_available) + { + hb_log(" - Intel Media SDK software: API %d.%d (minimum: %d.%d)", + qsv_software_version.Major, + qsv_software_version.Minor, + qsv_minimum_version.Major, + qsv_minimum_version.Minor); + } + hb_log(" - Preferred implementation: %s", + hb_qsv_impl_get_name(preferred_implementation)); + } +} + +const char* hb_qsv_decode_get_codec_name(enum AVCodecID codec_id) +{ + switch (codec_id) + { + case AV_CODEC_ID_H264: + return "h264_qsv"; + + default: + return NULL; + } +} + +int hb_qsv_decode_is_enabled(hb_job_t *job) +{ + return ((job != NULL && job->title->qsv_decode_support && job->qsv_decode) && + (job->vcodec & HB_VCODEC_QSV_MASK)); +} + +int hb_qsv_decode_is_supported(enum AVCodecID codec_id, + enum AVPixelFormat pix_fmt) +{ + switch (codec_id) + { + case AV_CODEC_ID_H264: + return (pix_fmt == AV_PIX_FMT_YUV420P || + pix_fmt == AV_PIX_FMT_YUVJ420P); + + default: + return 0; + } +} + +int hb_qsv_codingoption_xlat(int val) +{ + switch (HB_QSV_CLIP3(-1, 2, val)) + { + case 0: + return MFX_CODINGOPTION_OFF; + case 1: + case 2: // MFX_CODINGOPTION_ADAPTIVE, reserved + return MFX_CODINGOPTION_ON; + case -1: + default: + return MFX_CODINGOPTION_UNKNOWN; + } +} + +int hb_qsv_trellisvalue_xlat(int val) +{ + switch (HB_QSV_CLIP3(-1, 3, val)) + { + case 0: + return MFX_TRELLIS_OFF; + case 1: // I-frames only + return MFX_TRELLIS_I; + case 2: // I- and P-frames + return MFX_TRELLIS_I|MFX_TRELLIS_P; + case 3: // all frames + return MFX_TRELLIS_I|MFX_TRELLIS_P|MFX_TRELLIS_B; + case -1: + default: + return MFX_TRELLIS_UNKNOWN; + } +} + +const char* hb_qsv_codingoption_get_name(int val) +{ + switch (val) + { + case MFX_CODINGOPTION_ON: + return "on"; + case MFX_CODINGOPTION_OFF: + return "off"; + case MFX_CODINGOPTION_ADAPTIVE: + return "adaptive"; + case MFX_CODINGOPTION_UNKNOWN: + return "unknown (auto)"; + default: + return NULL; + } +} + +int hb_qsv_atoindex(const char* const *arr, const char *str, int *err) +{ + int i; + for (i = 0; arr[i] != NULL; i++) + { + if (!strcasecmp(arr[i], str)) + { + break; + } + } + *err = (arr[i] == NULL); + return i; +} + +// adapted from libx264 +int hb_qsv_atobool(const char *str, int *err) +{ + if (!strcasecmp(str, "1") || + !strcasecmp(str, "yes") || + !strcasecmp(str, "true")) + { + return 1; + } + if (!strcasecmp(str, "0") || + !strcasecmp(str, "no") || + !strcasecmp(str, "false")) + { + return 0; + } + *err = 1; + return 0; +} + +// adapted from libx264 +int hb_qsv_atoi(const char *str, int *err) +{ + char *end; + int v = strtol(str, &end, 0); + if (end == str || end[0] != '\0') + { + *err = 1; + } + return v; +} + +// adapted from libx264 +float hb_qsv_atof(const char *str, int *err) +{ + char *end; + float v = strtod(str, &end); + if (end == str || end[0] != '\0') + { + *err = 1; + } + return v; +} + +int hb_qsv_param_parse(hb_qsv_param_t *param, + const char *key, const char *value, int vcodec) +{ + float fvalue; + int ivalue, error = 0; + if (param == NULL) + { + return HB_QSV_PARAM_ERROR; + } + if (value == NULL || value[0] == '\0') + { + value = "true"; + } + else if (value[0] == '=') + { + value++; + } + if (key == NULL || key[0] == '\0') + { + return HB_QSV_PARAM_BAD_NAME; + } + else if (!strncasecmp(key, "no-", 3)) + { + key += 3; + value = hb_qsv_atobool(value, &error) ? "false" : "true"; + if (error) + { + return HB_QSV_PARAM_BAD_VALUE; + } + } + if (!strcasecmp(key, "target-usage") || + !strcasecmp(key, "tu")) + { + ivalue = hb_qsv_atoi(value, &error); + if (!error) + { + param->videoParam->mfx.TargetUsage = HB_QSV_CLIP3(MFX_TARGETUSAGE_1, + MFX_TARGETUSAGE_7, + ivalue); + } + } + else if (!strcasecmp(key, "num-ref-frame") || + !strcasecmp(key, "ref")) + { + ivalue = hb_qsv_atoi(value, &error); + if (!error) + { + param->videoParam->mfx.NumRefFrame = HB_QSV_CLIP3(0, 16, ivalue); + } + } + else if (!strcasecmp(key, "gop-ref-dist")) + { + ivalue = hb_qsv_atoi(value, &error); + if (!error) + { + param->videoParam->mfx.GopRefDist = HB_QSV_CLIP3(0, 32, ivalue); + } + } + else if (!strcasecmp(key, "gop-pic-size") || + !strcasecmp(key, "keyint")) + { + ivalue = hb_qsv_atoi(value, &error); + if (!error) + { + param->gop.gop_pic_size = HB_QSV_CLIP3(-1, UINT16_MAX, ivalue); + } + } + else if (!strcasecmp(key, "b-pyramid")) + { + if (hb_qsv_info->capabilities & HB_QSV_CAP_H264_BPYRAMID) + { + switch (vcodec) + { + case HB_VCODEC_QSV_H264: + ivalue = hb_qsv_atobool(value, &error); + break; + default: + return HB_QSV_PARAM_UNSUPPORTED; + } + if (!error) + { + param->gop.b_pyramid = ivalue; + } + } + else + { + return HB_QSV_PARAM_UNSUPPORTED; + } + } + else if (!strcasecmp(key, "scenecut")) + { + ivalue = hb_qsv_atobool(value, &error); + if (!error) + { + if (!ivalue) + { + param->videoParam->mfx.GopOptFlag |= MFX_GOP_STRICT; + } + else + { + param->videoParam->mfx.GopOptFlag &= ~MFX_GOP_STRICT; + } + } + } + else if (!strcasecmp(key, "cqp-offset-i")) + { + ivalue = hb_qsv_atoi(value, &error); + if (!error) + { + param->rc.cqp_offsets[0] = HB_QSV_CLIP3(INT16_MIN, INT16_MAX, ivalue); + } + } + else if (!strcasecmp(key, "cqp-offset-p")) + { + ivalue = hb_qsv_atoi(value, &error); + if (!error) + { + param->rc.cqp_offsets[1] = HB_QSV_CLIP3(INT16_MIN, INT16_MAX, ivalue); + } + } + else if (!strcasecmp(key, "cqp-offset-b")) + { + ivalue = hb_qsv_atoi(value, &error); + if (!error) + { + param->rc.cqp_offsets[2] = HB_QSV_CLIP3(INT16_MIN, INT16_MAX, ivalue); + } + } + else if (!strcasecmp(key, "vbv-init")) + { + fvalue = hb_qsv_atof(value, &error); + if (!error) + { + param->rc.vbv_buffer_init = HB_QSV_CLIP3(0, UINT16_MAX, fvalue); + } + } + else if (!strcasecmp(key, "vbv-bufsize")) + { + ivalue = hb_qsv_atoi(value, &error); + if (!error) + { + param->rc.vbv_buffer_size = HB_QSV_CLIP3(0, UINT16_MAX, ivalue); + } + } + else if (!strcasecmp(key, "vbv-maxrate")) + { + ivalue = hb_qsv_atoi(value, &error); + if (!error) + { + param->rc.vbv_max_bitrate = HB_QSV_CLIP3(0, UINT16_MAX, ivalue); + } + } + else if (!strcasecmp(key, "cabac")) + { + switch (vcodec) + { + case HB_VCODEC_QSV_H264: + ivalue = !hb_qsv_atobool(value, &error); + break; + default: + return HB_QSV_PARAM_UNSUPPORTED; + } + if (!error) + { + param->codingOption.CAVLC = hb_qsv_codingoption_xlat(ivalue); + } + } + else if (!strcasecmp(key, "rate-distorsion-opt") || + !strcasecmp(key, "rdo")) + { + switch (vcodec) + { + case HB_VCODEC_QSV_H264: + ivalue = hb_qsv_atobool(value, &error); + break; + default: + return HB_QSV_PARAM_UNSUPPORTED; + } + if (!error) + { + param->codingOption.RateDistortionOpt = hb_qsv_codingoption_xlat(ivalue); + } + } + else if (!strcasecmp(key, "videoformat")) + { + switch (vcodec) + { + case HB_VCODEC_QSV_H264: + ivalue = hb_qsv_atoindex(x264_vidformat_names, value, &error); + break; + default: + return HB_QSV_PARAM_UNSUPPORTED; + } + if (!error) + { + param->videoSignalInfo.VideoFormat = ivalue; + } + } + else if (!strcasecmp(key, "fullrange")) + { + switch (vcodec) + { + case HB_VCODEC_QSV_H264: + ivalue = hb_qsv_atoindex(x264_fullrange_names, value, &error); + break; + default: + return HB_QSV_PARAM_UNSUPPORTED; + } + if (!error) + { + param->videoSignalInfo.VideoFullRange = ivalue; + } + } + else if (!strcasecmp(key, "colorprim")) + { + switch (vcodec) + { + case HB_VCODEC_QSV_H264: + ivalue = hb_qsv_atoindex(x264_colorprim_names, value, &error); + break; + default: + return HB_QSV_PARAM_UNSUPPORTED; + } + if (!error) + { + param->videoSignalInfo.ColourDescriptionPresent = 1; + param->videoSignalInfo.ColourPrimaries = ivalue; + } + } + else if (!strcasecmp(key, "transfer")) + { + switch (vcodec) + { + case HB_VCODEC_QSV_H264: + ivalue = hb_qsv_atoindex(x264_transfer_names, value, &error); + break; + default: + return HB_QSV_PARAM_UNSUPPORTED; + } + if (!error) + { + param->videoSignalInfo.ColourDescriptionPresent = 1; + param->videoSignalInfo.TransferCharacteristics = ivalue; + } + } + else if (!strcasecmp(key, "colormatrix")) + { + switch (vcodec) + { + case HB_VCODEC_QSV_H264: + ivalue = hb_qsv_atoindex(x264_colmatrix_names, value, &error); + break; + default: + return HB_QSV_PARAM_UNSUPPORTED; + } + if (!error) + { + param->videoSignalInfo.ColourDescriptionPresent = 1; + param->videoSignalInfo.MatrixCoefficients = ivalue; + } + } + else if (!strcasecmp(key, "tff") || + !strcasecmp(key, "interlaced")) + { + switch (vcodec) + { + case HB_VCODEC_QSV_H264: + ivalue = hb_qsv_atobool(value, &error); + break; + default: + return HB_QSV_PARAM_UNSUPPORTED; + } + if (!error) + { + param->videoParam->mfx.FrameInfo.PicStruct = (ivalue ? + MFX_PICSTRUCT_FIELD_TFF : + MFX_PICSTRUCT_PROGRESSIVE); + } + } + else if (!strcasecmp(key, "bff")) + { + switch (vcodec) + { + case HB_VCODEC_QSV_H264: + ivalue = hb_qsv_atobool(value, &error); + break; + default: + return HB_QSV_PARAM_UNSUPPORTED; + } + if (!error) + { + param->videoParam->mfx.FrameInfo.PicStruct = (ivalue ? + MFX_PICSTRUCT_FIELD_BFF : + MFX_PICSTRUCT_PROGRESSIVE); + } + } + else if (!strcasecmp(key, "mbbrc")) + { + if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_BRC) + { + ivalue = hb_qsv_atoi(value, &error); + if (!error) + { + param->codingOption2.MBBRC = hb_qsv_codingoption_xlat(ivalue); + } + } + else + { + return HB_QSV_PARAM_UNSUPPORTED; + } + } + else if (!strcasecmp(key, "extbrc")) + { + if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_BRC) + { + ivalue = hb_qsv_atoi(value, &error); + if (!error) + { + param->codingOption2.ExtBRC = hb_qsv_codingoption_xlat(ivalue); + } + } + else + { + return HB_QSV_PARAM_UNSUPPORTED; + } + } + else if (!strcasecmp(key, "lookahead") || + !strcasecmp(key, "la")) + { + switch (vcodec) + { + case HB_VCODEC_QSV_H264: + ivalue = hb_qsv_atobool(value, &error); + break; + default: + return HB_QSV_PARAM_UNSUPPORTED; + } + if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_LOOKAHEAD) + { + if (!error) + { + param->rc.lookahead = ivalue; + } + } + else + { + return HB_QSV_PARAM_UNSUPPORTED; + } + } + else if (!strcasecmp(key, "lookahead-depth") || + !strcasecmp(key, "la-depth")) + { + switch (vcodec) + { + case HB_VCODEC_QSV_H264: + ivalue = hb_qsv_atoi(value, &error); + break; + default: + return HB_QSV_PARAM_UNSUPPORTED; + } + if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_LOOKAHEAD) + { + if (!error) + { + param->codingOption2.LookAheadDepth = HB_QSV_CLIP3(10, 100, + ivalue); + } + } + else + { + return HB_QSV_PARAM_UNSUPPORTED; + } + } + else if (!strcasecmp(key, "trellis")) + { + switch (vcodec) + { + case HB_VCODEC_QSV_H264: + ivalue = hb_qsv_atoi(value, &error); + break; + default: + return HB_QSV_PARAM_UNSUPPORTED; + } + if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_TRELLIS) + { + if (!error) + { + param->codingOption2.Trellis = hb_qsv_trellisvalue_xlat(ivalue); + } + } + else + { + return HB_QSV_PARAM_UNSUPPORTED; + } + } + else + { + /* + * TODO: + * - slice count control + * - open-gop + * - fake-interlaced (mfxExtCodingOption.FramePicture???) + * - intra-refresh + */ + return HB_QSV_PARAM_BAD_NAME; + } + return error ? HB_QSV_PARAM_BAD_VALUE : HB_QSV_PARAM_OK; +} + +int hb_qsv_param_default(hb_qsv_param_t *param, mfxVideoParam *videoParam) +{ + if (param != NULL && videoParam != NULL) + { + // introduced in API 1.0 + memset(¶m->codingOption, 0, sizeof(mfxExtCodingOption)); + param->codingOption.Header.BufferId = MFX_EXTBUFF_CODING_OPTION; + param->codingOption.Header.BufferSz = sizeof(mfxExtCodingOption); + param->codingOption.MECostType = 0; // reserved, must be 0 + param->codingOption.MESearchType = 0; // reserved, must be 0 + param->codingOption.MVSearchWindow.x = 0; // reserved, must be 0 + param->codingOption.MVSearchWindow.y = 0; // reserved, must be 0 + param->codingOption.RefPicListReordering = 0; // reserved, must be 0 + param->codingOption.IntraPredBlockSize = 0; // reserved, must be 0 + param->codingOption.InterPredBlockSize = 0; // reserved, must be 0 + param->codingOption.MVPrecision = 0; // reserved, must be 0 + param->codingOption.EndOfSequence = MFX_CODINGOPTION_UNKNOWN; + param->codingOption.RateDistortionOpt = MFX_CODINGOPTION_UNKNOWN; + param->codingOption.CAVLC = MFX_CODINGOPTION_UNKNOWN; + param->codingOption.ResetRefList = MFX_CODINGOPTION_UNKNOWN; + param->codingOption.MaxDecFrameBuffering = 0; // unspecified + param->codingOption.AUDelimiter = MFX_CODINGOPTION_OFF; + param->codingOption.SingleSeiNalUnit = MFX_CODINGOPTION_UNKNOWN; + param->codingOption.PicTimingSEI = MFX_CODINGOPTION_OFF; + param->codingOption.VuiNalHrdParameters = MFX_CODINGOPTION_UNKNOWN; + param->codingOption.FramePicture = MFX_CODINGOPTION_UNKNOWN; + // introduced in API 1.3 + param->codingOption.RefPicMarkRep = MFX_CODINGOPTION_UNKNOWN; + param->codingOption.FieldOutput = MFX_CODINGOPTION_UNKNOWN; + param->codingOption.NalHrdConformance = MFX_CODINGOPTION_UNKNOWN; + param->codingOption.SingleSeiNalUnit = MFX_CODINGOPTION_UNKNOWN; + param->codingOption.VuiVclHrdParameters = MFX_CODINGOPTION_UNKNOWN; + // introduced in API 1.4 + param->codingOption.ViewOutput = MFX_CODINGOPTION_UNKNOWN; + // introduced in API 1.6 + param->codingOption.RecoveryPointSEI = MFX_CODINGOPTION_UNKNOWN; + + // introduced in API 1.3 + memset(¶m->videoSignalInfo, 0, sizeof(mfxExtVideoSignalInfo)); + param->videoSignalInfo.Header.BufferId = MFX_EXTBUFF_VIDEO_SIGNAL_INFO; + param->videoSignalInfo.Header.BufferSz = sizeof(mfxExtVideoSignalInfo); + param->videoSignalInfo.VideoFormat = 5; // undefined + param->videoSignalInfo.VideoFullRange = 0; // TV range + param->videoSignalInfo.ColourDescriptionPresent = 0; // don't write to bitstream + param->videoSignalInfo.ColourPrimaries = 2; // undefined + param->videoSignalInfo.TransferCharacteristics = 2; // undefined + param->videoSignalInfo.MatrixCoefficients = 2; // undefined + + // introduced in API 1.6 + memset(¶m->codingOption2, 0, sizeof(mfxExtCodingOption2)); + param->codingOption2.Header.BufferId = MFX_EXTBUFF_CODING_OPTION2; + param->codingOption2.Header.BufferSz = sizeof(mfxExtCodingOption2); + param->codingOption2.IntRefType = 0; + param->codingOption2.IntRefCycleSize = 2; + param->codingOption2.IntRefQPDelta = 0; + param->codingOption2.MaxFrameSize = 0; + param->codingOption2.BitrateLimit = MFX_CODINGOPTION_ON; + param->codingOption2.ExtBRC = MFX_CODINGOPTION_OFF; + param->codingOption2.MBBRC = MFX_CODINGOPTION_UNKNOWN; + // introduced in API 1.7 + param->codingOption2.LookAheadDepth = 40; + param->codingOption2.Trellis = MFX_TRELLIS_UNKNOWN; + + // GOP & rate control + param->gop.b_pyramid = 0; + param->gop.gop_pic_size = -1; // set automatically + param->gop.int_ref_cycle_size = -1; // set automatically + param->rc.lookahead = -1; // set automatically + param->rc.cqp_offsets[0] = 0; + param->rc.cqp_offsets[1] = 2; + param->rc.cqp_offsets[2] = 4; + param->rc.vbv_max_bitrate = 0; // set automatically + param->rc.vbv_buffer_size = 0; // set automatically + param->rc.vbv_buffer_init = .0; // set automatically + + // introduced in API 1.0 + memset(videoParam, 0, sizeof(mfxVideoParam)); + param->videoParam = videoParam; + param->videoParam->Protected = 0; // reserved, must be 0 + param->videoParam->NumExtParam = 0; + param->videoParam->IOPattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY; + param->videoParam->mfx.TargetUsage = MFX_TARGETUSAGE_2; + param->videoParam->mfx.GopOptFlag = MFX_GOP_CLOSED; + param->videoParam->mfx.NumThread = 0; // deprecated, must be 0 + param->videoParam->mfx.EncodedOrder = 0; // input is in display order + param->videoParam->mfx.IdrInterval = 0; // all I-frames are IDR + param->videoParam->mfx.NumSlice = 0; // use Media SDK default + param->videoParam->mfx.NumRefFrame = 0; // use Media SDK default + param->videoParam->mfx.GopPicSize = 0; // use Media SDK default + param->videoParam->mfx.GopRefDist = 0; // use Media SDK default + // introduced in API 1.1 + param->videoParam->AsyncDepth = AV_QSV_ASYNC_DEPTH_DEFAULT; + // introduced in API 1.3 + param->videoParam->mfx.BRCParamMultiplier = 0; // no multiplier + + // FrameInfo: set by video encoder, except PicStruct + param->videoParam->mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE; + + // attach supported mfxExtBuffer structures to the mfxVideoParam + param->videoParam->NumExtParam = 0; + param->videoParam->ExtParam = param->ExtParamArray; + param->videoParam->ExtParam[param->videoParam->NumExtParam++] = (mfxExtBuffer*)¶m->codingOption; + param->videoParam->ExtParam[param->videoParam->NumExtParam++] = (mfxExtBuffer*)¶m->videoSignalInfo; + if (hb_qsv_info->capabilities & HB_QSV_CAP_MSDK_API_1_6) + { + param->videoParam->ExtParam[param->videoParam->NumExtParam++] = (mfxExtBuffer*)¶m->codingOption2; + } + } + else + { + hb_error("hb_qsv_param_default: invalid pointer(s)"); + return -1; + } + return 0; +} + +mfxIMPL hb_qsv_impl_get_preferred() +{ + return preferred_implementation; +} + +const char* hb_qsv_impl_get_name(int impl) +{ + switch (MFX_IMPL_BASETYPE(impl)) + { + case MFX_IMPL_SOFTWARE: + return "software"; + + case MFX_IMPL_HARDWARE: + return "hardware (1)"; + case MFX_IMPL_HARDWARE2: + return "hardware (2)"; + case MFX_IMPL_HARDWARE3: + return "hardware (3)"; + case MFX_IMPL_HARDWARE4: + return "hardware (4)"; + case MFX_IMPL_HARDWARE_ANY: + return "hardware (any)"; + + case MFX_IMPL_AUTO: + return "automatic"; + case MFX_IMPL_AUTO_ANY: + return "automatic (any)"; + + default: + return NULL; + } +} diff --git a/libhb/qsv_common.h b/libhb/qsv_common.h new file mode 100644 index 000000000..418180432 --- /dev/null +++ b/libhb/qsv_common.h @@ -0,0 +1,125 @@ +/* qsv_common.h + * + * 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 + */ + +#ifndef HB_QSV_COMMON_H +#define HB_QSV_COMMON_H + +#include "msdk/mfxvideo.h" +#include "libavcodec/avcodec.h" + +/* Minimum Intel Media SDK version (currently 1.3, for Sandy Bridge support) */ +#define HB_QSV_MINVERSION_MAJOR AV_QSV_MSDK_VERSION_MAJOR +#define HB_QSV_MINVERSION_MINOR AV_QSV_MSDK_VERSION_MINOR + +/* + * Get & store all available Intel Quick Sync information: + * + * - general availability + * - available implementations (hardware-accelerated, software fallback, etc.) + * - available codecs, filters, etc. for direct access (convenience) + * - supported API version + * - supported resolutions + */ +typedef struct hb_qsv_info_s +{ + // supported version-specific or hardware-specific capabilities + int capabilities; +#define HB_QSV_CAP_H264_BPYRAMID (1 << 0) // H.264: reference B-frames +#define HB_QSV_CAP_MSDK_API_1_6 (1 << 1) // Support for API 1.6 or later +#define HB_QSV_CAP_OPTION2_BRC (1 << 2) // mfxExtCodingOption2: MBBRC/ExtBRC +#define HB_QSV_CAP_OPTION2_LOOKAHEAD (1 << 3) // mfxExtCodingOption2: LookAhead +#define HB_QSV_CAP_OPTION2_TRELLIS (1 << 4) // mfxExtCodingOption2: Trellis + + // TODO: add available decoders, filters, encoders, + // maximum decode and encode resolution, etc. +} hb_qsv_info_t; + +/* Global Intel QSV information for use by the UIs */ +extern hb_qsv_info_t *hb_qsv_info; + +/* Intel Quick Sync Video utilities */ +int hb_qsv_available(); +int hb_qsv_info_init(); +void hb_qsv_info_print(); + +/* Intel Quick Sync Video DECODE utilities */ +const char* hb_qsv_decode_get_codec_name(enum AVCodecID codec_id); +int hb_qsv_decode_is_enabled(hb_job_t *job); +int hb_qsv_decode_is_supported(enum AVCodecID codec_id, enum AVPixelFormat pix_fmt); + +/* Media SDK parameters handling */ +enum +{ + HB_QSV_PARAM_OK, + HB_QSV_PARAM_ERROR, + HB_QSV_PARAM_BAD_NAME, + HB_QSV_PARAM_BAD_VALUE, + HB_QSV_PARAM_UNSUPPORTED, +}; + +typedef struct +{ + /* + * Supported mfxExtBuffer.BufferId values: + * + * MFX_EXTBUFF_AVC_REFLIST_CTRL + * MFX_EXTBUFF_AVC_TEMPORAL_LAYERS + * MFX_EXTBUFF_CODING_OPTION + * MFX_EXTBUFF_CODING_OPTION_SPSPPS + * MFX_EXTBUFF_CODING_OPTION2 + * MFX_EXTBUFF_ENCODER_CAPABILITY + * MFX_EXTBUFF_ENCODER_RESET_OPTION + * MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION + * MFX_EXTBUFF_PICTURE_TIMING_SEI + * MFX_EXTBUFF_VIDEO_SIGNAL_INFO + * + * This should cover all encode-compatible extended + * buffers that can be attached to an mfxVideoParam. + */ +#define HB_QSV_ENC_NUM_EXT_PARAM_MAX 10 + mfxExtBuffer* ExtParamArray[HB_QSV_ENC_NUM_EXT_PARAM_MAX]; + mfxExtCodingOption codingOption; + mfxExtCodingOption2 codingOption2; + mfxExtVideoSignalInfo videoSignalInfo; + struct + { + int b_pyramid; + int gop_pic_size; + int int_ref_cycle_size; + } gop; + struct + { + int lookahead; + int cqp_offsets[3]; + int vbv_max_bitrate; + int vbv_buffer_size; + float vbv_buffer_init; + } rc; + + // assigned via hb_qsv_param_default, may be shared with another structure + mfxVideoParam *videoParam; +} hb_qsv_param_t; + +#define HB_QSV_CLIP3(min, max, val) ((val < min) ? min : (val > max) ? max : val) +int hb_qsv_codingoption_xlat (int val); +const char* hb_qsv_codingoption_get_name(int val); + +int hb_qsv_trellisvalue_xlat(int val); +int hb_qsv_atoindex(const char* const *arr, const char *str, int *err); +int hb_qsv_atobool (const char *str, int *err); +int hb_qsv_atoi (const char *str, int *err); +float hb_qsv_atof (const char *str, int *err); + +int hb_qsv_param_default(hb_qsv_param_t *param, mfxVideoParam *videoParam); +int hb_qsv_param_parse (hb_qsv_param_t *param, const char *key, const char *value, int vcodec); + +mfxIMPL hb_qsv_impl_get_preferred(); +const char* hb_qsv_impl_get_name(int impl); + +#endif diff --git a/libhb/qsv_filter.c b/libhb/qsv_filter.c new file mode 100644 index 000000000..3de9d6254 --- /dev/null +++ b/libhb/qsv_filter.c @@ -0,0 +1,648 @@ +/* ********************************************************************* *\ + +Copyright (C) 2013 Intel Corporation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. +- Neither the name of Intel Corporation nor the names of its contributors +may be used to endorse or promote products derived from this software +without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +\* ********************************************************************* */ + +#include "hb.h" +#include "hbffmpeg.h" +#include "libavcodec/qsv.h" +#include "qsv_filter.h" +#include "enc_qsv.h" + +struct hb_filter_private_s +{ + hb_job_t *job; + hb_list_t *list; + + int width_in; + int height_in; + int pix_fmt; + int pix_fmt_out; + int width_out; + int height_out; + int crop[4]; + int deinterlace; + int is_frc_used; + + av_qsv_space *vpp_space; + + // FRC param(s) + mfxExtVPPFrameRateConversion frc_config; +}; + +static int hb_qsv_filter_init( hb_filter_object_t * filter, + hb_filter_init_t * init ); + +static int hb_qsv_filter_work( hb_filter_object_t * filter, + hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ); + +static int hb_qsv_filter_info( hb_filter_object_t * filter, + hb_filter_info_t * info ); + +static void hb_qsv_filter_close( hb_filter_object_t * filter ); + +hb_filter_object_t hb_filter_qsv = +{ + .id = HB_FILTER_QSV, + .enforce_order = 1, + .name = "Quick Sync Video VPP", + .settings = NULL, + .init = hb_qsv_filter_init, + .work = hb_qsv_filter_work, + .close = hb_qsv_filter_close, + .info = hb_qsv_filter_info, +}; + +static int filter_init( av_qsv_context* qsv, hb_filter_private_t * pv ){ + mfxStatus sts; + int i=0; + + if(!qsv) return 3; + + + if(!qsv->vpp_space){ + qsv->vpp_space = av_qsv_list_init(HAVE_THREADS); + } + if(!pv->vpp_space){ + for(i=0; i<av_qsv_list_count(qsv->vpp_space);i++){ + av_qsv_space *qsv_vpp = av_qsv_list_item( qsv->vpp_space, i ); + if(qsv_vpp->type == AV_QSV_VPP_DEFAULT){ + pv->vpp_space = qsv_vpp; + break; + } + } + } + + if(!pv->vpp_space){ + pv->vpp_space = calloc( 1, sizeof( av_qsv_space )); + pv->vpp_space->type = AV_QSV_VPP_DEFAULT; + av_qsv_list_add( qsv->vpp_space, pv->vpp_space ); + } + else + if(pv->vpp_space->is_init_done ) return 1; + + if(!qsv->dec_space || !qsv->dec_space->is_init_done) return 2; + + // we need to know final output settings before we can properly configure + if (!pv->job->qsv_enc_info.is_init_done) + { + return 2; + } + + av_qsv_add_context_usage(qsv,HAVE_THREADS); + + // see params needed like at mediasdk-man.pdf:"Appendix A: Configuration Parameter Constraints" + // for now - most will take from the decode + { + av_qsv_space *qsv_vpp = pv->vpp_space; + AV_QSV_ZERO_MEMORY(qsv_vpp->m_mfxVideoParam); + + if (pv->deinterlace) + { + /* + * Input may be progressive, interlaced or even mixed, so init with + * MFX_PICSTRUCT_UNKNOWN and use per-frame field order information + * (mfxFrameSurface1.Info.PicStruct) + */ + qsv_vpp->m_mfxVideoParam.vpp.In.PicStruct = MFX_PICSTRUCT_UNKNOWN; + qsv_vpp->m_mfxVideoParam.vpp.Out.PicStruct = MFX_PICSTRUCT_PROGRESSIVE; + } + else + { + /* Same PicStruct in/out: no filtering */ + qsv_vpp->m_mfxVideoParam.vpp.In.PicStruct = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.PicStruct; + qsv_vpp->m_mfxVideoParam.vpp.Out.PicStruct = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.PicStruct; + } + + // FrameRate is important for VPP to start with + if( qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtN == 0 && + qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtD == 0 ){ + qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtN = pv->job->title->rate; + qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtD = pv->job->title->rate_base; + } + + qsv_vpp->m_mfxVideoParam.vpp.In.FourCC = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FourCC; + qsv_vpp->m_mfxVideoParam.vpp.In.ChromaFormat = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.ChromaFormat; + qsv_vpp->m_mfxVideoParam.vpp.In.CropX = pv->crop[2]; + qsv_vpp->m_mfxVideoParam.vpp.In.CropY = pv->crop[0]; + qsv_vpp->m_mfxVideoParam.vpp.In.CropW = pv-> width_in - pv->crop[3] - pv->crop[2]; + qsv_vpp->m_mfxVideoParam.vpp.In.CropH = pv->height_in - pv->crop[1] - pv->crop[0]; + qsv_vpp->m_mfxVideoParam.vpp.In.FrameRateExtN = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtN; + qsv_vpp->m_mfxVideoParam.vpp.In.FrameRateExtD = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtD; + qsv_vpp->m_mfxVideoParam.vpp.In.AspectRatioW = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.AspectRatioW; + qsv_vpp->m_mfxVideoParam.vpp.In.AspectRatioH = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.AspectRatioH; + qsv_vpp->m_mfxVideoParam.vpp.In.Width = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.Width; + qsv_vpp->m_mfxVideoParam.vpp.In.Height = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.Height; + + qsv_vpp->m_mfxVideoParam.vpp.Out.FourCC = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FourCC; + qsv_vpp->m_mfxVideoParam.vpp.Out.ChromaFormat = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.ChromaFormat; + qsv_vpp->m_mfxVideoParam.vpp.Out.CropX = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.CropX; + qsv_vpp->m_mfxVideoParam.vpp.Out.CropY = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.CropY; + qsv_vpp->m_mfxVideoParam.vpp.Out.CropW = pv->width_out; + qsv_vpp->m_mfxVideoParam.vpp.Out.CropH = pv->height_out; + qsv_vpp->m_mfxVideoParam.vpp.Out.FrameRateExtN = pv->job->vrate; + qsv_vpp->m_mfxVideoParam.vpp.Out.FrameRateExtD = pv->job->vrate_base; + qsv_vpp->m_mfxVideoParam.vpp.Out.AspectRatioW = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.AspectRatioW; + qsv_vpp->m_mfxVideoParam.vpp.Out.AspectRatioH = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.AspectRatioH; + qsv_vpp->m_mfxVideoParam.vpp.Out.Width = pv->job->qsv_enc_info.align_width; + qsv_vpp->m_mfxVideoParam.vpp.Out.Height = pv->job->qsv_enc_info.align_height; + + qsv_vpp->m_mfxVideoParam.IOPattern = MFX_IOPATTERN_IN_OPAQUE_MEMORY | MFX_IOPATTERN_OUT_OPAQUE_MEMORY; + + qsv_vpp->m_mfxVideoParam.AsyncDepth = pv->job->qsv_async_depth; + + memset(&qsv_vpp->request, 0, sizeof(mfxFrameAllocRequest)*2); + + sts = MFXVideoVPP_QueryIOSurf(qsv->mfx_session, &qsv_vpp->m_mfxVideoParam, qsv_vpp->request ); + AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + int num_surfaces_in = qsv_vpp->request[0].NumFrameSuggested; + int num_surfaces_out = qsv_vpp->request[1].NumFrameSuggested; + + av_qsv_config *config = qsv->qsv_config; + + + qsv_vpp->surface_num = FFMIN( num_surfaces_in + num_surfaces_out + qsv_vpp->m_mfxVideoParam.AsyncDepth + config ? config->additional_buffers/2 :0 , AV_QSV_SURFACE_NUM ); + if(qsv_vpp->surface_num <= 0 ) + qsv_vpp->surface_num = AV_QSV_SURFACE_NUM; + + int i = 0; + for (i = 0; i < qsv_vpp->surface_num; i++){ + qsv_vpp->p_surfaces[i] = av_mallocz( sizeof(mfxFrameSurface1) ); + AV_QSV_CHECK_POINTER(qsv_vpp->p_surfaces[i], MFX_ERR_MEMORY_ALLOC); + memcpy(&(qsv_vpp->p_surfaces[i]->Info), &(qsv_vpp->m_mfxVideoParam.vpp.Out), sizeof(mfxFrameInfo)); + } + + qsv_vpp->sync_num = FFMIN( qsv_vpp->surface_num, AV_QSV_SYNC_NUM ); + + for (i = 0; i < qsv_vpp->sync_num; i++){ + qsv_vpp->p_syncp[i] = av_mallocz(sizeof(av_qsv_sync)); + AV_QSV_CHECK_POINTER(qsv_vpp->p_syncp[i], MFX_ERR_MEMORY_ALLOC); + qsv_vpp->p_syncp[i]->p_sync = av_mallocz(sizeof(mfxSyncPoint)); + AV_QSV_CHECK_POINTER(qsv_vpp->p_syncp[i]->p_sync, MFX_ERR_MEMORY_ALLOC); + } +/* + about available VPP filters, see "Table 4 Configurable VPP filters", mediasdk-man.pdf + Hints (optional feature) IDs: + MFX_EXTBUFF_VPP_DENOISE // Remove noise + // Value of 0-100 (inclusive) indicates + // the level of noise to remove. + MFX_EXTBUFF_VPP_DETAIL // Enhance picture details/edges: + // 0-100 value (inclusive) to indicate + // the level of details to be enhanced. + MFX_EXTBUFF_VPP_FRAME_RATE_CONVERSION // Convert input frame rate to match the output, based on frame interpolation: + // MFX_FRCALGM_PRESERVE_TIMESTAMP, + // MFX_FRCALGM_DISTRIBUTED_TIMESTAMP, + // MFX_FRCALGM_FRAME_INTERPOLATION + MFX_EXTBUFF_VPP_IMAGE_STABILIZATION // Perform image stabilization + // Stabilization modes: + // MFX_IMAGESTAB_MODE_UPSCALE + // MFX_IMAGESTAB_MODE_BOXING + MFX_EXTBUFF_VPP_PICSTRUCT_DETECTION // Perform detection of picture structure: + // Detected picture structure - top field first, bottom field first, progressive or unknown + // if video processor cannot detect picture structure. + MFX_EXTBUFF_VPP_PROCAMP // Adjust the brightness, contrast, saturation, and hue settings + + // Initialize extended buffer for frame processing + // - Process amplifier (ProcAmp) used to control brightness + // - mfxExtVPPDoUse: Define the processing algorithm to be used + // - mfxExtVPPProcAmp: ProcAmp configuration + // - mfxExtBuffer: Add extended buffers to VPP parameter configuration + mfxExtVPPDoUse extDoUse; + mfxU32 tabDoUseAlg[1]; + extDoUse.Header.BufferId = MFX_EXTBUFF_VPP_DOUSE; + extDoUse.Header.BufferSz = sizeof(mfxExtVPPDoUse); + extDoUse.NumAlg = 1; + extDoUse.AlgList = tabDoUseAlg; + tabDoUseAlg[0] = MFX_EXTBUFF_VPP_PROCAMP; + + mfxExtVPPProcAmp procampConfig; + procampConfig.Header.BufferId = MFX_EXTBUFF_VPP_PROCAMP; + procampConfig.Header.BufferSz = sizeof(mfxExtVPPProcAmp); + procampConfig.Hue = 0.0f; // Default + procampConfig.Saturation = 1.0f; // Default + procampConfig.Contrast = 1.0; // Default + procampConfig.Brightness = 40.0; // Adjust brightness + + mfxExtBuffer* ExtBuffer[2]; + ExtBuffer[0] = (mfxExtBuffer*)&extDoUse; + ExtBuffer[1] = (mfxExtBuffer*)&procampConfig; + VPPParams.NumExtParam = 2; + VPPParams.ExtParam = (mfxExtBuffer**)&ExtBuffer[0]; +*/ + memset(&qsv_vpp->ext_opaque_alloc, 0, sizeof(qsv_vpp->ext_opaque_alloc)); + + if( (qsv_vpp->m_mfxVideoParam.vpp.In.FrameRateExtN / qsv_vpp->m_mfxVideoParam.vpp.In.FrameRateExtD ) != + (qsv_vpp->m_mfxVideoParam.vpp.Out.FrameRateExtN / qsv_vpp->m_mfxVideoParam.vpp.Out.FrameRateExtD) ) + { + pv->is_frc_used = 1; + } + + qsv_vpp->m_mfxVideoParam.NumExtParam = qsv_vpp->p_ext_param_num = 1 + pv->is_frc_used; + + qsv_vpp->p_ext_params = av_mallocz(sizeof(mfxExtBuffer *)*qsv_vpp->p_ext_param_num); + AV_QSV_CHECK_POINTER(qsv_vpp->p_ext_params, MFX_ERR_MEMORY_ALLOC); + + qsv_vpp->m_mfxVideoParam.ExtParam = qsv_vpp->p_ext_params; + + qsv_vpp->ext_opaque_alloc.In.Surfaces = qsv->dec_space->p_surfaces; + qsv_vpp->ext_opaque_alloc.In.NumSurface = qsv->dec_space->surface_num; + qsv_vpp->ext_opaque_alloc.In.Type = qsv->dec_space->request[0].Type; + + qsv_vpp->ext_opaque_alloc.Out.Surfaces = qsv_vpp->p_surfaces; + qsv_vpp->ext_opaque_alloc.Out.NumSurface = qsv_vpp->surface_num; + qsv_vpp->ext_opaque_alloc.Out.Type = qsv->dec_space->request[0].Type; + + qsv_vpp->ext_opaque_alloc.Header.BufferId = MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION; + qsv_vpp->ext_opaque_alloc.Header.BufferSz = sizeof(mfxExtOpaqueSurfaceAlloc); + qsv_vpp->p_ext_params[0] = (mfxExtBuffer*)&qsv_vpp->ext_opaque_alloc; + + if(pv->is_frc_used) + { + pv->frc_config.Header.BufferId = MFX_EXTBUFF_VPP_FRAME_RATE_CONVERSION; + pv->frc_config.Header.BufferSz = sizeof(mfxExtVPPFrameRateConversion); + pv->frc_config.Algorithm = MFX_FRCALGM_PRESERVE_TIMESTAMP; + + qsv_vpp->p_ext_params[1] = (mfxExtBuffer*)&pv->frc_config; + } + + sts = MFXVideoVPP_Init(qsv->mfx_session, &qsv_vpp->m_mfxVideoParam); + + AV_QSV_IGNORE_MFX_STS(sts, MFX_WRN_PARTIAL_ACCELERATION); + AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + qsv_vpp->is_init_done = 1; + } + return 0; +} + +static int hb_qsv_filter_init( hb_filter_object_t * filter, + hb_filter_init_t * init ) +{ + + filter->private_data = calloc( 1, sizeof(struct hb_filter_private_s) ); + hb_filter_private_t * pv = filter->private_data; + + pv->list = hb_list_init(); + // list of init params provided at work.c:~700 + pv->width_in = init->width; + pv->height_in = init->height; + pv->width_out = init->width; + pv->height_out = init->height; + memcpy( pv->crop, init->crop, sizeof( int[4] ) ); + + if (filter->settings != NULL) + { + sscanf(filter->settings, "%d:%d:%d:%d:%d:%d_dei:%d", + &pv->width_out, &pv->height_out, + &pv->crop[0], &pv->crop[1], &pv->crop[2], &pv->crop[3], + &pv->deinterlace); + } + + pv->job = init->job; + + // will be later as more params will be known + // filter_init(pv->job->qsv, pv); + + // just passing + init->vrate = init->vrate; + init->vrate_base = init->vrate_base; + + // framerate shaping not yet supported + init->cfr = 0; + + init->pix_fmt = pv->pix_fmt; + init->width = pv->width_out; + init->height = pv->height_out; + memcpy( init->crop, pv->crop, sizeof( int[4] ) ); + + return 0; +} + +static int hb_qsv_filter_info( hb_filter_object_t * filter, + hb_filter_info_t * info ) +{ + + hb_filter_private_t *pv = filter->private_data; + if (pv == NULL) + return -1; + + sprintf(info->human_readable_desc, + "source: %d * %d, crop (%d/%d/%d/%d): %d * %d, scale: %d * %d", + pv->width_in, pv->height_in, + pv->crop[0], pv->crop[1], pv->crop[2], pv->crop[3], + pv->width_in - pv->crop[2] - pv->crop[3], + pv->height_in - pv->crop[0] - pv->crop[1], + pv->width_out, pv->height_out); + + if (pv->deinterlace) + { + sprintf(info->human_readable_desc + strlen(info->human_readable_desc), + ", deinterlace"); + } + + return 0; +} + +void qsv_filter_close( av_qsv_context* qsv, AV_QSV_STAGE_TYPE vpp_type ){ + int i = 0; + av_qsv_space* vpp_space = 0; + + if(qsv && qsv->is_context_active && qsv->vpp_space) + for(i=av_qsv_list_count( qsv->vpp_space);i>0;i--){ + + vpp_space = av_qsv_list_item( qsv->vpp_space, i-1 ); + if( vpp_space->type == vpp_type && vpp_space->is_init_done){ + + hb_log( "qsv_filter[%s] done: max_surfaces: %u/%u , max_syncs: %u/%u", ((vpp_type == AV_QSV_VPP_DEFAULT)?"Default": "User") ,vpp_space->surface_num_max_used, vpp_space->surface_num, vpp_space->sync_num_max_used, vpp_space->sync_num ); + + for (i = 0; i < vpp_space->surface_num; i++){ + av_freep(&vpp_space->p_surfaces[i]); + } + vpp_space->surface_num = 0; + + if( vpp_space->p_ext_param_num || vpp_space->p_ext_params ) + av_freep(&vpp_space->p_ext_params); + vpp_space->p_ext_param_num = 0; + + for (i = 0; i < vpp_space->sync_num; i++){ + av_freep(&vpp_space->p_syncp[i]->p_sync); + av_freep(&vpp_space->p_syncp[i]); + } + vpp_space->sync_num = 0; + + av_qsv_list_rem(qsv->vpp_space,vpp_space); + if( av_qsv_list_count(qsv->vpp_space) == 0 ) + av_qsv_list_close(&qsv->vpp_space); + + vpp_space->is_init_done = 0; + break; + } + } +} + +static void hb_qsv_filter_close( hb_filter_object_t * filter ) +{ + int i = 0; + hb_filter_private_t * pv = filter->private_data; + + if ( !pv ) + { + return; + } + + av_qsv_context* qsv = pv->job->qsv; + if(qsv && qsv->vpp_space && av_qsv_list_count(qsv->vpp_space) > 0){ + + // closing local stuff + qsv_filter_close(qsv,AV_QSV_VPP_DEFAULT); + + // closing the commong stuff + av_qsv_context_clean(qsv); + } + hb_list_close(&pv->list); + free( pv ); + filter->private_data = NULL; +} + +int process_frame(av_qsv_list* received_item, av_qsv_context* qsv, hb_filter_private_t * pv ){ + + // 1 if have results , 0 - otherwise + int ret = 1; + + mfxStatus sts = MFX_ERR_NONE; + mfxFrameSurface1 *work_surface = NULL; + av_qsv_stage* stage = 0; + + av_qsv_space *qsv_vpp = pv->vpp_space; + + if(received_item){ + stage = av_qsv_get_last_stage( received_item ); + work_surface = stage->out.p_surface; + } + + int sync_idx = av_qsv_get_free_sync(qsv_vpp, qsv); + int surface_idx = -1; + + for(;;) + { + if (sync_idx == -1) + { + hb_error("qsv: Not enough resources allocated for QSV filter"); + ret = 0; + break; + } + if( sts == MFX_ERR_MORE_SURFACE || sts == MFX_ERR_NONE ) + surface_idx = av_qsv_get_free_surface(qsv_vpp, qsv, &(qsv_vpp->m_mfxVideoParam.vpp.Out), QSV_PART_ANY); + if (surface_idx == -1) { + hb_error("qsv: Not enough resources allocated for QSV filter"); + ret = 0; + break; + } + if (work_surface) { + work_surface->Info.CropX = pv->crop[2]; + work_surface->Info.CropY = pv->crop[0]; + work_surface->Info.CropW = pv->width_in - pv->crop[3] - pv->crop[2]; + work_surface->Info.CropH = pv->height_in - pv->crop[1] - pv->crop[0]; + } + + sts = MFXVideoVPP_RunFrameVPPAsync(qsv->mfx_session, work_surface, qsv_vpp->p_surfaces[surface_idx] , NULL, qsv_vpp->p_syncp[sync_idx]->p_sync); + + if( MFX_ERR_MORE_DATA == sts ){ + if(!qsv_vpp->pending){ + qsv_vpp->pending = av_qsv_list_init(0); + } + + // if we have no results, we should not miss resource(s) + av_qsv_list_add( qsv_vpp->pending, received_item); + + ff_qsv_atomic_dec(&qsv_vpp->p_syncp[sync_idx]->in_use); + + ret = 0; + break; + } + + if( MFX_ERR_MORE_DATA == sts || (MFX_ERR_NONE <= sts && MFX_WRN_DEVICE_BUSY != sts)){ + if (work_surface){ + ff_qsv_atomic_dec(&work_surface->Data.Locked); + } + } + + if( MFX_ERR_MORE_SURFACE == sts || MFX_ERR_NONE <= sts){ + if( MFX_ERR_MORE_SURFACE == sts ) + continue; + + if (qsv_vpp->p_surfaces[surface_idx] && MFX_WRN_DEVICE_BUSY != sts ) + ff_qsv_atomic_inc(&qsv_vpp->p_surfaces[surface_idx]->Data.Locked); + } + + AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + if (MFX_ERR_NONE <= sts ) // repeat the call if warning and no output + { + if (MFX_WRN_DEVICE_BUSY == sts){ + av_qsv_sleep(10); // wait if device is busy + continue; + } + + // shouldnt be a case but drain + if(stage){ + av_qsv_stage* new_stage = av_qsv_stage_init(); + + new_stage->type = AV_QSV_VPP_DEFAULT; + new_stage->in.p_surface = work_surface; + new_stage->out.p_surface = qsv_vpp->p_surfaces[surface_idx]; + new_stage->out.sync = qsv_vpp->p_syncp[sync_idx]; + av_qsv_add_stagee( &received_item, new_stage,HAVE_THREADS ); + + // add pending resources for the proper reclaim later + if( qsv_vpp->pending ){ + if( av_qsv_list_count(qsv_vpp->pending)>0 ){ + new_stage->pending = qsv_vpp->pending; + } + qsv_vpp->pending = 0; + + // making free via decrement for all pending + int i = 0; + for (i = av_qsv_list_count(new_stage->pending); i > 0; i--){ + av_qsv_list *atom_list = av_qsv_list_item(new_stage->pending, i-1); + av_qsv_stage *stage = av_qsv_get_last_stage( atom_list ); + mfxFrameSurface1 *work_surface = stage->out.p_surface; + if (work_surface) + ff_qsv_atomic_dec(&work_surface->Data.Locked); + } + } + } + break; + } + + ff_qsv_atomic_dec(&qsv_vpp->p_syncp[sync_idx]->in_use); + + if (MFX_ERR_NOT_ENOUGH_BUFFER == sts) + DEBUG_ASSERT( 1,"The bitstream buffer size is insufficient." ); + + break; + } + + return ret; +} + +static int hb_qsv_filter_work( hb_filter_object_t * filter, + hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ) +{ + + hb_filter_private_t * pv = filter->private_data; + hb_buffer_t * in = *buf_in; + hb_buffer_t * out = *buf_out; + int sts = 0; + + av_qsv_context* qsv = pv->job->qsv; + + if ( !pv ) + { + *buf_out = in; + *buf_in = NULL; + return HB_FILTER_OK; + } + + while(1){ + int ret = filter_init(qsv,pv); + if(ret >= 2) + av_qsv_sleep(1); + else + break; + } + + *buf_in = NULL; + + if ( in->size <= 0 ) + { + while(1){ + sts = process_frame(in->qsv_details.qsv_atom, qsv, pv); + if(sts) + hb_list_add(pv->list,in); + else + break; + } + + hb_list_add( pv->list, in ); + *buf_out = link_buf_list( pv ); + return HB_FILTER_DONE; + } + + sts = process_frame(in->qsv_details.qsv_atom, qsv, pv); + + if(sts){ + hb_list_add(pv->list,in); + } + + if( hb_list_count(pv->list) ){ + *buf_out = hb_list_item(pv->list,0); + out = *buf_out; + if(pv->is_frc_used && out) + { + mfxStatus sts = MFX_ERR_NONE; + if(out->qsv_details.qsv_atom){ + av_qsv_stage* stage = av_qsv_get_last_stage( out->qsv_details.qsv_atom ); + mfxFrameSurface1 *work_surface = stage->out.p_surface; + + av_qsv_wait_on_sync( qsv,stage ); + + av_qsv_space *qsv_vpp = pv->vpp_space; + int64_t duration = ((double)qsv_vpp->m_mfxVideoParam.vpp.Out.FrameRateExtD/(double)qsv_vpp->m_mfxVideoParam.vpp.Out.FrameRateExtN ) * 90000.; + out->s.start = work_surface->Data.TimeStamp; + out->s.stop = work_surface->Data.TimeStamp + duration; + } + } + hb_list_rem(pv->list,*buf_out); + } + else + *buf_out = NULL; + + return HB_FILTER_OK; +} + +// see devavcode.c +hb_buffer_t *link_buf_list( hb_filter_private_t *pv ) +{ + hb_buffer_t *head = hb_list_item( pv->list, 0 ); + + if ( head ) + { + hb_list_rem( pv->list, head ); + hb_buffer_t *last = head, *buf; + while ( ( buf = hb_list_item( pv->list, 0 ) ) != NULL ) + { + hb_list_rem( pv->list, buf ); + last->next = buf; + last = buf; + } + } + return head; +} + diff --git a/libhb/qsv_filter.h b/libhb/qsv_filter.h new file mode 100644 index 000000000..e55a85cdf --- /dev/null +++ b/libhb/qsv_filter.h @@ -0,0 +1,35 @@ +/* ********************************************************************* *\ + +Copyright (C) 2013 Intel Corporation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. +- Neither the name of Intel Corporation nor the names of its contributors +may be used to endorse or promote products derived from this software +without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +\* ********************************************************************* */ + +#ifndef QSV_FILTER_H +#define QSV_FILTER_H + +hb_buffer_t *link_buf_list( hb_filter_private_t *pv ); +void qsv_filter_close( av_qsv_context* qsv, AV_QSV_STAGE_TYPE vpp_type ); + +#endif // QSV_FILTER_H diff --git a/libhb/qsv_filter_pp.c b/libhb/qsv_filter_pp.c new file mode 100644 index 000000000..1aef1eb80 --- /dev/null +++ b/libhb/qsv_filter_pp.c @@ -0,0 +1,916 @@ +/* ********************************************************************* *\ + +Copyright (C) 2013 Intel Corporation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. +- Neither the name of Intel Corporation nor the names of its contributors +may be used to endorse or promote products derived from this software +without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +\* ********************************************************************* */ + +#include "hb.h" +#include "hbffmpeg.h" +#include "libavcodec/qsv.h" +#include "qsv_filter_pp.h" +#include "qsv_filter.h" +#include "qsv_memory.h" + + +static int hb_qsv_filter_pre_init( hb_filter_object_t * filter, + hb_filter_init_t * init ); +static int hb_qsv_filter_pre_work( hb_filter_object_t * filter, + hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ); +static int hb_qsv_filter_pre_info( hb_filter_object_t * filter, + hb_filter_info_t * info ); +static void hb_qsv_filter_pre_close( hb_filter_object_t * filter ); + +static int hb_qsv_filter_post_init( hb_filter_object_t * filter, + hb_filter_init_t * init ); +static int hb_qsv_filter_post_work( hb_filter_object_t * filter, + hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ); +static int hb_qsv_filter_post_info( hb_filter_object_t * filter, + hb_filter_info_t * info ); +static void hb_qsv_filter_post_close( hb_filter_object_t * filter ); + + +hb_filter_object_t hb_filter_qsv_pre = +{ + .id = HB_FILTER_QSV_PRE, + .enforce_order = 1, + .name = "Quick Sync Video user filter (pre)", + .settings = NULL, + .init = hb_qsv_filter_pre_init, + .work = hb_qsv_filter_pre_work, + .close = hb_qsv_filter_pre_close, + .info = hb_qsv_filter_pre_info, +}; + +hb_filter_object_t hb_filter_qsv_post = +{ + .id = HB_FILTER_QSV_POST, + .enforce_order = 1, + .name = "Quick Sync Video user filter (post)", + .settings = NULL, + .init = hb_qsv_filter_post_init, + .work = hb_qsv_filter_post_work, + .close = hb_qsv_filter_post_close, + .info = hb_qsv_filter_post_info, +}; + + +static int filter_pre_init( av_qsv_context* qsv, hb_filter_private_t * pv ){ + mfxStatus sts = MFX_ERR_NONE; + int i=0; + + if(!qsv) return 3; + + av_qsv_space *prev_vpp = 0; + + if(!qsv->vpp_space){ + qsv->vpp_space = av_qsv_list_init(HAVE_THREADS); + // note some change as : when no size changes -> no VPP used + // impact on : prev_vpp + } + + if(!pv->vpp_space){ + for(i=0; i<av_qsv_list_count(qsv->vpp_space);i++){ + av_qsv_space *qsv_vpp = av_qsv_list_item( qsv->vpp_space, i ); + if(qsv_vpp->type == AV_QSV_VPP_USER){ + pv->vpp_space = qsv_vpp; + break; + } + else + if(qsv_vpp->type == AV_QSV_VPP_DEFAULT){ + prev_vpp = qsv_vpp; + } + + } + } + + if(!pv->vpp_space){ + pv->vpp_space = calloc( 1, sizeof( av_qsv_space )); + pv->vpp_space->type = AV_QSV_VPP_USER; + av_qsv_list_add( qsv->vpp_space, pv->vpp_space ); + av_qsv_add_context_usage(qsv,HAVE_THREADS); + } + else + if(pv->vpp_space->is_init_done ) return 1; + + if(!qsv->dec_space || !qsv->dec_space->is_init_done) return 2; + + av_qsv_space *qsv_vpp = pv->vpp_space; + + AV_QSV_ZERO_MEMORY(qsv_vpp->m_mfxVideoParam); + + + if (prev_vpp) + { + memcpy( &qsv_vpp->m_mfxVideoParam.vpp, &prev_vpp->m_mfxVideoParam.vpp, sizeof(prev_vpp->m_mfxVideoParam.vpp)); + } + else + { + AV_QSV_ZERO_MEMORY(qsv_vpp->m_mfxVideoParam); + + // FrameRate is important for VPP to start with + if( qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtN == 0 && + qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtD == 0 ){ + qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtN = pv->job->title->rate; + qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtD = pv->job->title->rate_base; + } + + qsv_vpp->m_mfxVideoParam.vpp.In.FourCC = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FourCC; + qsv_vpp->m_mfxVideoParam.vpp.In.ChromaFormat = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.ChromaFormat; + qsv_vpp->m_mfxVideoParam.vpp.In.CropX = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.CropX; + qsv_vpp->m_mfxVideoParam.vpp.In.CropY = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.CropY; + qsv_vpp->m_mfxVideoParam.vpp.In.CropW = pv->job->title->width; + qsv_vpp->m_mfxVideoParam.vpp.In.CropH = pv->job->title->height; + qsv_vpp->m_mfxVideoParam.vpp.In.PicStruct = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.PicStruct; + qsv_vpp->m_mfxVideoParam.vpp.In.FrameRateExtN = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtN; + qsv_vpp->m_mfxVideoParam.vpp.In.FrameRateExtD = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtD; + qsv_vpp->m_mfxVideoParam.vpp.In.AspectRatioW = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.AspectRatioW; + qsv_vpp->m_mfxVideoParam.vpp.In.AspectRatioH = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.AspectRatioH; + qsv_vpp->m_mfxVideoParam.vpp.In.Width = AV_QSV_ALIGN16(pv->job->title->width); + qsv_vpp->m_mfxVideoParam.vpp.In.Height = (MFX_PICSTRUCT_PROGRESSIVE == qsv_vpp->m_mfxVideoParam.vpp.In.PicStruct)? + AV_QSV_ALIGN16(pv->job->title->height) : AV_QSV_ALIGN32(pv->job->title->height); + + qsv_vpp->m_mfxVideoParam.vpp.Out.FourCC = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FourCC; + qsv_vpp->m_mfxVideoParam.vpp.Out.ChromaFormat = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.ChromaFormat; + qsv_vpp->m_mfxVideoParam.vpp.Out.CropX = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.CropX; + qsv_vpp->m_mfxVideoParam.vpp.Out.CropY = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.CropY; + qsv_vpp->m_mfxVideoParam.vpp.Out.CropW = pv->job->title->width; + qsv_vpp->m_mfxVideoParam.vpp.Out.CropH = pv->job->title->height; + qsv_vpp->m_mfxVideoParam.vpp.Out.PicStruct = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.PicStruct; + qsv_vpp->m_mfxVideoParam.vpp.Out.FrameRateExtN = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtN; + qsv_vpp->m_mfxVideoParam.vpp.Out.FrameRateExtD = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtD; + qsv_vpp->m_mfxVideoParam.vpp.Out.AspectRatioW = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.AspectRatioW; + qsv_vpp->m_mfxVideoParam.vpp.Out.AspectRatioH = qsv->dec_space->m_mfxVideoParam.mfx.FrameInfo.AspectRatioH; + qsv_vpp->m_mfxVideoParam.vpp.Out.Width = AV_QSV_ALIGN16(pv->job->title->width); + qsv_vpp->m_mfxVideoParam.vpp.Out.Height = (MFX_PICSTRUCT_PROGRESSIVE == qsv_vpp->m_mfxVideoParam.vpp.In.PicStruct)? + AV_QSV_ALIGN16(pv->job->title->height) : AV_QSV_ALIGN32(pv->job->title->height); + + memset(&qsv_vpp->request, 0, sizeof(mfxFrameAllocRequest)*2); + } + + qsv_vpp->m_mfxVideoParam.IOPattern = MFX_IOPATTERN_IN_OPAQUE_MEMORY | MFX_IOPATTERN_OUT_OPAQUE_MEMORY; + + qsv_vpp->surface_num = FFMIN(prev_vpp ? prev_vpp->surface_num : qsv->dec_space->surface_num/2, AV_QSV_SURFACE_NUM); + + for(i = 0; i < qsv_vpp->surface_num; i++){ + qsv_vpp->p_surfaces[i] = av_mallocz( sizeof(mfxFrameSurface1) ); + AV_QSV_CHECK_POINTER(qsv_vpp->p_surfaces[i], MFX_ERR_MEMORY_ALLOC); + memcpy(&(qsv_vpp->p_surfaces[i]->Info), &(qsv_vpp->m_mfxVideoParam.vpp.Out), sizeof(mfxFrameInfo)); + } + + qsv_vpp->sync_num = FFMIN(prev_vpp ? prev_vpp->sync_num : qsv->dec_space->sync_num, AV_QSV_SYNC_NUM); + for (i = 0; i < qsv_vpp->sync_num; i++){ + qsv_vpp->p_syncp[i] = av_mallocz(sizeof(av_qsv_sync)); + AV_QSV_CHECK_POINTER(qsv_vpp->p_syncp[i], MFX_ERR_MEMORY_ALLOC); + qsv_vpp->p_syncp[i]->p_sync = av_mallocz(sizeof(mfxSyncPoint)); + AV_QSV_CHECK_POINTER(qsv_vpp->p_syncp[i]->p_sync, MFX_ERR_MEMORY_ALLOC); + } + + memset(&qsv_vpp->ext_opaque_alloc, 0, sizeof(mfxExtOpaqueSurfaceAlloc)); + qsv_vpp->m_mfxVideoParam.NumExtParam = qsv_vpp->p_ext_param_num = 1; + + qsv_vpp->p_ext_params = av_mallocz(sizeof(mfxExtBuffer *)*qsv_vpp->p_ext_param_num); + AV_QSV_CHECK_POINTER(qsv_vpp->p_ext_params, MFX_ERR_MEMORY_ALLOC); + + qsv_vpp->m_mfxVideoParam.ExtParam = qsv_vpp->p_ext_params; + + qsv_vpp->ext_opaque_alloc.Header.BufferId = MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION; + qsv_vpp->ext_opaque_alloc.Header.BufferSz = sizeof(mfxExtOpaqueSurfaceAlloc); + qsv_vpp->p_ext_params[0] = (mfxExtBuffer*)&qsv_vpp->ext_opaque_alloc; + + if(prev_vpp){ + qsv_vpp->ext_opaque_alloc.In.Surfaces = prev_vpp->p_surfaces; + qsv_vpp->ext_opaque_alloc.In.NumSurface = prev_vpp->surface_num; + } + else{ + qsv_vpp->ext_opaque_alloc.In.Surfaces = qsv->dec_space->p_surfaces; + qsv_vpp->ext_opaque_alloc.In.NumSurface = qsv->dec_space->surface_num; + } + qsv_vpp->ext_opaque_alloc.In.Type = qsv->dec_space->request[0].Type; + + qsv_vpp->ext_opaque_alloc.Out.Surfaces = qsv_vpp->p_surfaces; + qsv_vpp->ext_opaque_alloc.Out.NumSurface = qsv_vpp->surface_num; + qsv_vpp->ext_opaque_alloc.Out.Type = qsv->dec_space->request[0].Type; + + pv->qsv_user = hb_list_init(); + + qsv_filter_t *plugin = av_mallocz( sizeof(qsv_filter_t) ); + + plugin->pv = pv; + plugin->plug.pthis = plugin; + plugin->plug.PluginInit = qsv_PluginInit; + plugin->plug.PluginClose = qsv_PluginClose; + plugin->plug.GetPluginParam = qsv_GetPluginParam; + plugin->plug.Submit = qsv_Submit; + plugin->plug.Execute = qsv_Execute; + plugin->plug.FreeResources = qsv_FreeResources; + + hb_list_add(pv->qsv_user,plugin); + + sts=MFXVideoUSER_Register(qsv->mfx_session,0,&plugin->plug); + AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + plugin_init(plugin,&qsv_vpp->m_mfxVideoParam); + + qsv_vpp->is_init_done = 1; + + return 0; +} + +static int hb_qsv_filter_pre_info( hb_filter_object_t * filter, + hb_filter_info_t * info ){ + hb_filter_private_t * pv = filter->private_data; + if( !pv ) + return 0; + + sprintf(info->human_readable_desc, "copy data to system memory"); + + return 0; +} +static int hb_qsv_filter_pre_init( hb_filter_object_t * filter, + hb_filter_init_t * init ){ + filter->private_data = calloc( 1, sizeof(struct hb_filter_private_s) ); + hb_filter_private_t * pv = filter->private_data; + pv->job = init->job; + + pv->pre.frame_go = 0; + pv->pre.frame_completed = hb_cond_init(); + pv->pre.frame_completed_lock = hb_lock_init(); + + pv->post.frame_go = 0; + pv->post.frame_completed = hb_cond_init(); + pv->post.frame_completed_lock = hb_lock_init(); + + pv->pre_busy.frame_go = 0; + pv->pre_busy.frame_completed = hb_cond_init(); + pv->pre_busy.frame_completed_lock = hb_lock_init(); + + pv->post_busy.frame_go = 0; + pv->post_busy.frame_completed = hb_cond_init(); + pv->post_busy.frame_completed_lock = hb_lock_init(); + + pv->list = hb_list_init(); + + // just to remind: + // PIX_FMT_YUV420P, ///< planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples) , 3 planes: Y, U, V + // PIX_FMT_NV12, ///< planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (first byte U and the following byte V) + pv->sws_context_from_nv12 = hb_sws_get_context( + pv->job->title->width, pv->job->title->height, AV_PIX_FMT_NV12, + pv->job->title->width, pv->job->title->height, AV_PIX_FMT_YUV420P, + SWS_LANCZOS|SWS_ACCURATE_RND); + pv->sws_context_to_nv12 = hb_sws_get_context( + pv->job->title->width, pv->job->title->height, AV_PIX_FMT_YUV420P, + pv->job->title->width, pv->job->title->height, AV_PIX_FMT_NV12, + SWS_LANCZOS|SWS_ACCURATE_RND); + return 0; +} +int pre_process_frame(hb_buffer_t *in, av_qsv_context* qsv, hb_filter_private_t * pv ){ + + // 1 if have results , 0 otherwise + int ret = 1; + + av_qsv_list* received_item = in->qsv_details.qsv_atom; + + mfxStatus sts = MFX_ERR_NONE; + mfxFrameSurface1 *work_surface = NULL; + av_qsv_stage* stage = 0; + + av_qsv_space *qsv_vpp = pv->vpp_space; + + if (received_item) + { + stage = av_qsv_get_last_stage( received_item ); + work_surface = stage->out.p_surface; + } + + int sync_idx = av_qsv_get_free_sync(qsv_vpp, qsv); + int surface_idx = -1; + + for (;;) + { + if (sync_idx == -1) + { + hb_error("qsv: Not enough resources allocated for the preprocessing filter"); + ret = 0; + break; + } + + if (sts == MFX_ERR_MORE_SURFACE || sts == MFX_ERR_NONE) + surface_idx = av_qsv_get_free_surface(qsv_vpp, qsv, &(qsv_vpp->m_mfxVideoParam.vpp.Out), QSV_PART_ANY); + if (surface_idx == -1) { + hb_error("qsv: Not enough resources allocated for the preprocessing filter"); + ret = 0; + break; + } + + sts = MFXVideoUSER_ProcessFrameAsync(qsv->mfx_session, &work_surface, 1, &qsv_vpp->p_surfaces[surface_idx] , 1, qsv_vpp->p_syncp[sync_idx]->p_sync); + + if (MFX_ERR_MORE_DATA == sts) + { + if (!qsv_vpp->pending) + { + qsv_vpp->pending = av_qsv_list_init(0); + } + + // if we have no results, we should not miss resource(s) + av_qsv_list_add( qsv_vpp->pending, received_item); + + ff_qsv_atomic_dec(&qsv_vpp->p_syncp[sync_idx]->in_use); + + ret = 0; + break; + } + + if( MFX_ERR_MORE_SURFACE == sts || MFX_ERR_NONE <= sts){ + if( MFX_ERR_MORE_SURFACE == sts ) + continue; + + if (qsv_vpp->p_surfaces[surface_idx] && MFX_WRN_DEVICE_BUSY != sts ) + ff_qsv_atomic_inc(&qsv_vpp->p_surfaces[surface_idx]->Data.Locked); + } + + AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + if (MFX_ERR_NONE <= sts ) // repeat the call if warning and no output + { + if (MFX_WRN_DEVICE_BUSY == sts){ + hb_lock(pv->pre_busy.frame_completed_lock); + while(!pv->pre_busy.frame_go){ + hb_cond_timedwait(pv->pre_busy.frame_completed,pv->pre_busy.frame_completed_lock,1000); + if(*pv->job->die) + break; + } + pv->pre_busy.frame_go = 0; + hb_unlock(pv->pre_busy.frame_completed_lock); + + continue; + } + hb_lock(pv->pre.frame_completed_lock); + while(!pv->pre.frame_go){ + hb_cond_timedwait(pv->pre.frame_completed,pv->pre.frame_completed_lock,1000); + if(*pv->job->die) + break; + } + pv->pre.frame_go = 0; + hb_unlock(pv->pre.frame_completed_lock); + + in = pv->pre.out; + + if (work_surface){ + ff_qsv_atomic_dec(&work_surface->Data.Locked); + } + + // inserting for the future, will be locked until very ready + if(stage){ + av_qsv_stage* new_stage = av_qsv_stage_init(); + + new_stage->type = AV_QSV_VPP_USER; + new_stage->in.p_surface = work_surface; + new_stage->out.p_surface = qsv_vpp->p_surfaces[surface_idx]; + new_stage->out.sync = qsv_vpp->p_syncp[sync_idx]; + av_qsv_add_stagee( &received_item, new_stage,HAVE_THREADS ); + + // add pending resources for the proper reclaim later + if( qsv_vpp->pending ){ + if( av_qsv_list_count(qsv_vpp->pending)>0 ){ + new_stage->pending = qsv_vpp->pending; + } + qsv_vpp->pending = 0; + + // making free via decrement for all pending + int i = 0; + for (i = av_qsv_list_count(new_stage->pending); i > 0; i--){ + av_qsv_list *atom_list = av_qsv_list_item(new_stage->pending, i-1); + av_qsv_stage *stage = av_qsv_get_last_stage( atom_list ); + mfxFrameSurface1 *work_surface = stage->out.p_surface; + if (work_surface) + ff_qsv_atomic_dec(&work_surface->Data.Locked); + } + } + } + + break; + } + + ff_qsv_atomic_dec(&qsv_vpp->p_syncp[sync_idx]->in_use); + + if (MFX_ERR_NOT_ENOUGH_BUFFER == sts) + DEBUG_ASSERT( 1,"The bitstream buffer size is insufficient." ); + + break; + } + + return ret; +} + +static int hb_qsv_filter_pre_work( hb_filter_object_t * filter, + hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ){ + hb_filter_private_t * pv = filter->private_data; + hb_buffer_t * in = *buf_in; + hb_buffer_t * out = *buf_out; + int sts = 0; + + av_qsv_context* qsv = pv->job->qsv; + + if(!in->qsv_details.filter_details) + in->qsv_details.filter_details = pv; + + if ( in->size <= 0 ) + { + *buf_out = in; + *buf_in = NULL; + return HB_FILTER_DONE; + } + + while(1){ + int ret = filter_pre_init(qsv,pv); + if(ret >= 2) + av_qsv_sleep(1); + else + break; + } + + pv->pre.in = in; + pv->pre.out = in; + + sts = pre_process_frame(in, qsv, pv); + + if(sts){ + hb_list_add(pv->list,out); + } + + if( hb_list_count(pv->list) ){ + *buf_out = hb_list_item(pv->list,0); + hb_list_rem(pv->list,*buf_out); + *buf_in = NULL; + } + else{ + *buf_in = NULL; + *buf_out = in; + } + + return HB_FILTER_OK; +} +static void hb_qsv_filter_pre_close( hb_filter_object_t * filter ){ + int i = 0; + mfxStatus sts = MFX_ERR_NONE; + + hb_filter_private_t * pv = filter->private_data; + + if ( !pv ) + { + return; + } + + sws_freeContext(pv->sws_context_to_nv12); + sws_freeContext(pv->sws_context_from_nv12); + + av_qsv_context* qsv = pv->job->qsv; + if(qsv && qsv->vpp_space && av_qsv_list_count(qsv->vpp_space) > 0 ){ + if(pv->qsv_user && qsv->mfx_session){ + + sts=MFXVideoUSER_Unregister(qsv->mfx_session,0); + AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + for(i=hb_list_count(pv->qsv_user);i>0;i--){ + qsv_filter_t *plugin = hb_list_item(pv->qsv_user,i-1); + hb_list_rem(pv->qsv_user,plugin); + plugin_close(plugin); + } + hb_list_close(&pv->qsv_user); + } + + // closing local stuff + qsv_filter_close(qsv,AV_QSV_VPP_USER); + + // closing the commong stuff + av_qsv_context_clean(qsv); + } + hb_cond_close(&pv->pre.frame_completed); + hb_lock_close(&pv->pre.frame_completed_lock); + + hb_cond_close(&pv->post.frame_completed); + hb_lock_close(&pv->post.frame_completed_lock); + + hb_cond_close(&pv->pre_busy.frame_completed); + hb_lock_close(&pv->pre_busy.frame_completed_lock); + + hb_cond_close(&pv->post_busy.frame_completed); + hb_lock_close(&pv->post_busy.frame_completed_lock); + + hb_list_close( &pv->list ); + + free( pv ); + filter->private_data = NULL; +} + + +static int hb_qsv_filter_post_info( hb_filter_object_t * filter, + hb_filter_info_t * info ){ + hb_filter_private_t * pv = filter->private_data; + if( !pv ) + return 0; + + sprintf(info->human_readable_desc, "copy data to opaque memory"); + + return 0; +} +static int hb_qsv_filter_post_init( hb_filter_object_t * filter, + hb_filter_init_t * init ){ + filter->private_data = calloc( 1, sizeof(struct hb_filter_private_s) ); + hb_filter_private_t * pv = filter->private_data; + pv->job = init->job; + return 0; +} +static int hb_qsv_filter_post_work( hb_filter_object_t * filter, + hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ){ + hb_filter_private_t * pv = filter->private_data; + hb_buffer_t * in = *buf_in; + hb_buffer_t * out = *buf_out; + + if ( in->size <= 0 ) + { + *buf_out = in; + *buf_in = NULL; + return HB_FILTER_DONE; + } + + av_qsv_context* qsv = pv->job->qsv; + pv = in->qsv_details.filter_details; + + if (!pv) + { + *buf_out = NULL; + *buf_in = NULL; + return HB_FILTER_OK; + } + + while(1){ + int ret = filter_pre_init(qsv,pv); + if(ret >= 2) + av_qsv_sleep(1); + else + break; + } + + pv->post.in = in; + pv->post.out = out; + + // signal: input is prepared, can start inserting data back into pipeline + hb_lock(pv->post.frame_completed_lock); + pv->post.frame_go = 1; + hb_cond_broadcast(pv->post.frame_completed); + hb_unlock(pv->post.frame_completed_lock); + + // wait: on signal that data is ready + hb_lock(pv->post_busy.frame_completed_lock); + while(!pv->post_busy.frame_go){ + hb_cond_timedwait(pv->post_busy.frame_completed,pv->post_busy.frame_completed_lock,1000); + if(*pv->job->die) + break; + } + pv->post_busy.frame_go = 0; + hb_unlock(pv->post_busy.frame_completed_lock); + + if (pv->post.status == HB_FILTER_OK || pv->post.status == HB_FILTER_DONE) + { + *buf_out = in; + } + else + { + *buf_out = NULL; + pv->post.status = HB_FILTER_OK; + } + *buf_in = NULL; + + return HB_FILTER_OK; +} +static void hb_qsv_filter_post_close( hb_filter_object_t * filter ){ + hb_filter_private_t * pv = filter->private_data; + + if ( !pv ) + { + return; + } + + free( pv ); + filter->private_data = NULL; +} + + +mfxStatus MFX_CDECL qsv_PluginInit(mfxHDL pthis, mfxCoreInterface *core){ + mfxStatus sts = MFX_ERR_NONE; + + if(core && pthis){ + qsv_filter_t *plugin = pthis; + plugin->core = core; + + plugin->pluginparam.MaxThreadNum = 1; + plugin->pluginparam.ThreadPolicy = MFX_THREADPOLICY_SERIAL; + } + else + sts = MFX_ERR_NULL_PTR; + + return sts; +} +mfxStatus MFX_CDECL qsv_PluginClose (mfxHDL pthis){ + mfxStatus sts = MFX_ERR_NONE; + return sts; +} +mfxStatus MFX_CDECL qsv_GetPluginParam(mfxHDL pthis, mfxPluginParam *par){ + mfxStatus sts = MFX_ERR_NONE; + + if(pthis){ + qsv_filter_t *plugin = pthis; + *par = plugin->pluginparam; + } + else + sts = MFX_ERR_NULL_PTR; + return sts; +} +mfxStatus MFX_CDECL qsv_Submit(mfxHDL pthis, const mfxHDL *in, mfxU32 in_num, const mfxHDL *out, mfxU32 out_num, mfxThreadTask *task){ + mfxStatus sts = MFX_ERR_NONE; + + qsv_filter_t *plugin = pthis; + + mfxFrameSurface1 *surface_in = (mfxFrameSurface1 *)in[0]; + mfxFrameSurface1 *surface_out = (mfxFrameSurface1 *)out[0]; + mfxFrameSurface1 *real_surface_in = surface_in; + mfxFrameSurface1 *real_surface_out = surface_out; + + sts = plugin->core->GetRealSurface(plugin->core->pthis, surface_in, &real_surface_in); + AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, MFX_ERR_MEMORY_ALLOC); + + sts = plugin->core->GetRealSurface(plugin->core->pthis, surface_out, &real_surface_out); + AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, MFX_ERR_MEMORY_ALLOC); + + int task_idx = get_free_task(plugin->tasks); + + if (task_idx == -1) + { + return MFX_WRN_DEVICE_BUSY; + } + + plugin->core->IncreaseReference(plugin->core->pthis, &(real_surface_in->Data)); + plugin->core->IncreaseReference(plugin->core->pthis, &(real_surface_out->Data)); + + // to preserve timing if other filters are used in-between + surface_out->Data.TimeStamp = surface_in->Data.TimeStamp; + surface_out->Data.FrameOrder = surface_in->Data.FrameOrder; + + qsv_filter_task_t *current_task = hb_list_item(plugin->tasks,task_idx); + current_task->in = real_surface_in; + current_task->out = real_surface_out; + current_task->busy = 1; + current_task->pv = plugin->pv; + + *task = (mfxThreadTask)current_task; + + return sts; +} +mfxStatus MFX_CDECL qsv_Execute(mfxHDL pthis, mfxThreadTask task, mfxU32 uid_p, mfxU32 uid_a){ + mfxStatus sts = MFX_ERR_NONE; + + qsv_filter_task_t *current_task = (qsv_filter_task_t *)task; + qsv_filter_t *plugin = pthis; + + sts = (current_task->processor.process)(current_task,0); + AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + sts = MFX_TASK_DONE; + return sts; +} +mfxStatus MFX_CDECL qsv_FreeResources(mfxHDL pthis, mfxThreadTask task, mfxStatus sts){ + + qsv_filter_t *plugin = pthis; + qsv_filter_task_t *current_task = (qsv_filter_task_t *)task; + + plugin->core->DecreaseReference(plugin->core->pthis, &(current_task->in->Data)); + plugin->core->DecreaseReference(plugin->core->pthis, &(current_task->out->Data)); + + current_task->busy = 0; + + hb_lock(plugin->pv->pre_busy.frame_completed_lock); + plugin->pv->pre_busy.frame_go = 1; + hb_cond_broadcast(plugin->pv->pre_busy.frame_completed); + hb_unlock(plugin->pv->pre_busy.frame_completed_lock); + + return MFX_ERR_NONE; +} + +mfxStatus plugin_init(qsv_filter_t* plugin, mfxVideoParam *param){ + mfxStatus sts = MFX_ERR_NONE; + + if(plugin->is_init_done) return sts; + + plugin->videoparam = param; + + mfxExtOpaqueSurfaceAlloc* plugin_opaque_alloc = NULL; + + plugin_opaque_alloc = (mfxExtOpaqueSurfaceAlloc*) get_ext_buffer(plugin->videoparam->ExtParam, + plugin->videoparam->NumExtParam, MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION); + + if(!plugin_opaque_alloc || !plugin_opaque_alloc->In.Surfaces || !plugin_opaque_alloc->Out.Surfaces) + return MFX_ERR_INVALID_VIDEO_PARAM; + + sts = plugin->core->MapOpaqueSurface(plugin->core->pthis, plugin_opaque_alloc->In.NumSurface, + plugin_opaque_alloc->In.Type, plugin_opaque_alloc->In.Surfaces); + AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + + sts = plugin->core->MapOpaqueSurface(plugin->core->pthis, plugin_opaque_alloc->Out.NumSurface, + plugin_opaque_alloc->Out.Type, plugin_opaque_alloc->Out.Surfaces); + AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + + plugin->tasks = hb_list_init(); + qsv_filter_task_t *task = calloc( 1, sizeof( qsv_filter_task_t )); + + task->processor.process = process_filter; + task->processor.alloc = &plugin->core->FrameAllocator; + task->processor.core = plugin->core; + + hb_list_add(plugin->tasks,task); + + plugin->is_init_done = 1; + + return sts; +} + +mfxStatus plugin_close(qsv_filter_t* plugin){ + int i = 0; + mfxStatus sts = MFX_ERR_NONE; + + if(!plugin->is_init_done) return sts; + + mfxExtOpaqueSurfaceAlloc* plugin_opaque_alloc = NULL; + + plugin_opaque_alloc = (mfxExtOpaqueSurfaceAlloc*) get_ext_buffer(plugin->videoparam->ExtParam, + plugin->videoparam->NumExtParam, MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION); + + if(!plugin_opaque_alloc || !plugin_opaque_alloc->In.Surfaces || !plugin_opaque_alloc->Out.Surfaces) + return MFX_ERR_INVALID_VIDEO_PARAM; + + sts = plugin->core->UnmapOpaqueSurface(plugin->core->pthis, plugin_opaque_alloc->In.NumSurface, + plugin_opaque_alloc->In.Type, plugin_opaque_alloc->In.Surfaces); + AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + + sts = plugin->core->UnmapOpaqueSurface(plugin->core->pthis, plugin_opaque_alloc->Out.NumSurface, + plugin_opaque_alloc->Out.Type, plugin_opaque_alloc->Out.Surfaces); + AV_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + if(plugin->tasks){ + for(i=hb_list_count(plugin->tasks);i>0;i--){ + qsv_filter_task_t *task = hb_list_item(plugin->tasks,i-1); + hb_list_rem(plugin->tasks,task); + free(task); + } + hb_list_close(&plugin->tasks); + } + + plugin->is_init_done = 0; + + return sts; +} + +mfxExtBuffer* get_ext_buffer(mfxExtBuffer** buffers, mfxU32 buffers_num, mfxU32 buffer_id){ + int i = 0; + if(!buffers) return 0; + for(i=0;i<buffers_num;i++){ + if(!buffers[i]) continue; + if(buffers[i]->BufferId == buffer_id) + return buffers[i]; + } + return 0; +} + +int get_free_task(hb_list_t* tasks){ + int ret = -1; + int i = 0; + for(i=0;i<hb_list_count(tasks);i++){ + qsv_filter_task_t* task = hb_list_item(tasks,i); + if(!task->busy){ + ret = i; + break; + } + } + return ret; +} + +mfxStatus lock_frame(mfxFrameAllocator *alloc,mfxFrameSurface1 *surface){ + mfxStatus sts = MFX_ERR_NONE; + // prevent double lock + if (surface->Data.Y != 0 && surface->Data.MemId !=0){ + return MFX_ERR_UNSUPPORTED; + } + // not allocated, therefore no lock + if (surface->Data.Y != 0){ + return MFX_ERR_NONE; + } + sts = alloc->Lock(alloc->pthis,surface->Data.MemId,&surface->Data); + return sts; +} + +mfxStatus unlock_frame(mfxFrameAllocator *alloc,mfxFrameSurface1 *surface){ + mfxStatus sts = MFX_ERR_NONE; + // not allocated + if (surface->Data.Y != 0 && surface->Data.MemId == 0){ + return MFX_ERR_NONE; + } + // not locked + if (surface->Data.Y == 0){ + return MFX_ERR_NONE; + } + sts = alloc->Unlock(alloc->pthis,surface->Data.MemId,&surface->Data); + return sts; +} + + +int process_filter(qsv_filter_task_t* task, void* params){ + mfxStatus sts = MFX_ERR_NONE; + + if (MFX_ERR_NONE != (sts = lock_frame(task->processor.alloc,task->in)))return sts; + if (MFX_ERR_NONE != (sts = lock_frame(task->processor.alloc,task->out))) + { + unlock_frame(task->processor.alloc,task->in); + return sts; + } + + qsv_nv12_to_yuv420(task->pv->sws_context_from_nv12,task->pv->pre.out, task->in, task->processor.core); + + // signal: input is prepared, converted from pipeline into internal buffer + hb_lock(task->pv->pre.frame_completed_lock); + task->pv->pre.frame_go = 1; + hb_cond_broadcast(task->pv->pre.frame_completed); + hb_unlock(task->pv->pre.frame_completed_lock); + + // wait: input is prepared, converted from pipeline into internal buffer + hb_lock(task->pv->post.frame_completed_lock); + while(!task->pv->post.frame_go){ + hb_cond_timedwait(task->pv->post.frame_completed,task->pv->post.frame_completed_lock,1000); + if(*task->pv->job->die) + break; + } + task->pv->post.frame_go = 0; + hb_unlock(task->pv->post.frame_completed_lock); + +// this is just a simple fun/test case +#if 0 + { + int i = 0; + char *cur_line; + char* luma = task->pv->post.in->plane[0].data; + int pitch = task->pv->post.in->plane[0].stride; + int h = task->pv->post.in->plane[0].height; + int w = task->pv->post.in->plane[0].width; + for (i = 0; i < h; i++){ + + cur_line = luma + i * pitch; + if(i>h/4 && i < 3*h/4 && i % 5 == 0 ) + memset(cur_line, 0 , w ); + } + } +#endif + + if(task->pv->post.in) + { + qsv_yuv420_to_nv12(task->pv->sws_context_to_nv12, task->out, task->pv->post.in); + } + + // signal: output is prepared, converted from internal buffer into pipeline + hb_lock(task->pv->post_busy.frame_completed_lock); + task->pv->post_busy.frame_go = 1; + hb_cond_broadcast(task->pv->post_busy.frame_completed); + hb_unlock(task->pv->post_busy.frame_completed_lock); + + unlock_frame(task->processor.alloc,task->in); + unlock_frame(task->processor.alloc,task->out); + + return sts; +} diff --git a/libhb/qsv_filter_pp.h b/libhb/qsv_filter_pp.h new file mode 100644 index 000000000..e70370321 --- /dev/null +++ b/libhb/qsv_filter_pp.h @@ -0,0 +1,114 @@ +/* ********************************************************************* *\ + +Copyright (C) 2013 Intel Corporation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. +- Neither the name of Intel Corporation nor the names of its contributors +may be used to endorse or promote products derived from this software +without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +\* ********************************************************************* */ + +#ifndef QSV_FILTER_PP_H +#define QSV_FILTER_PP_H + +#include "msdk/mfxplugin.h" + +extern hb_buffer_t *link_buf_list( hb_filter_private_t *pv ); + +struct qsv_filter_task_s; + +typedef struct{ + mfxFrameAllocator *alloc; + mfxStatus (*process)(struct qsv_filter_task_s*,void*); + mfxCoreInterface *core; +}qsv_filter_processor_t; + +typedef struct qsv_filter_task_s{ + mfxFrameSurface1 *in; + mfxFrameSurface1 *out; + int busy; + hb_filter_private_t *pv; + qsv_filter_processor_t processor; +} qsv_filter_task_t; + +typedef struct qsv_filter_private_s{ + + int is_init_done; + + mfxCoreInterface *core; + mfxVideoParam *videoparam; + mfxPluginParam pluginparam; + + hb_filter_private_t *pv; + + mfxPlugin plug; + hb_list_t *tasks; +} qsv_filter_t; + +typedef struct hb_qsv_sync_s{ + int frame_go; + int status; + hb_cond_t *frame_completed; + hb_lock_t *frame_completed_lock; + + hb_buffer_t *in; + hb_buffer_t *out; +} hb_qsv_sync_t; + +typedef struct hb_filter_private_s +{ + hb_job_t *job; + hb_list_t *list; + + hb_qsv_sync_t pre; + hb_qsv_sync_t pre_busy; + + hb_qsv_sync_t post; + hb_qsv_sync_t post_busy; + + av_qsv_space *vpp_space; + hb_list_t *qsv_user; + + struct SwsContext* sws_context_to_nv12; + struct SwsContext* sws_context_from_nv12; +} hb_filter_private_t_qsv; + +// methods to be called by Media SDK +mfxStatus MFX_CDECL qsv_PluginInit(mfxHDL pthis, mfxCoreInterface *core); +mfxStatus MFX_CDECL qsv_PluginClose (mfxHDL pthis); +mfxStatus MFX_CDECL qsv_GetPluginParam(mfxHDL pthis, mfxPluginParam *par); +mfxStatus MFX_CDECL qsv_Submit(mfxHDL pthis, const mfxHDL *in, mfxU32 in_num, const mfxHDL *out, mfxU32 out_num, mfxThreadTask *task); +mfxStatus MFX_CDECL qsv_Execute(mfxHDL pthis, mfxThreadTask task, mfxU32 uid_p, mfxU32 uid_a); +mfxStatus MFX_CDECL qsv_FreeResources(mfxHDL pthis, mfxThreadTask task, mfxStatus sts); + +// methods to be called by us +mfxStatus plugin_init(qsv_filter_t*,mfxVideoParam*); +mfxStatus plugin_close(qsv_filter_t*); + +//internal functions +mfxExtBuffer* get_ext_buffer(mfxExtBuffer**, mfxU32, mfxU32); +int get_free_task(hb_list_t*); +mfxStatus process_filter(qsv_filter_task_t*,void*); +mfxStatus lock_frame(mfxFrameAllocator *,mfxFrameSurface1*); +mfxStatus unlock_frame(mfxFrameAllocator *,mfxFrameSurface1*); + + +#endif //QSV_FILTER_PP_H diff --git a/libhb/qsv_memory.c b/libhb/qsv_memory.c new file mode 100644 index 000000000..f04c77a76 --- /dev/null +++ b/libhb/qsv_memory.c @@ -0,0 +1,120 @@ +/* ********************************************************************* *\ + +Copyright (C) 2013 Intel Corporation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. +- Neither the name of Intel Corporation nor the names of its contributors +may be used to endorse or promote products derived from this software +without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +\* ********************************************************************* */ + +#include "hb.h" +#include "hbffmpeg.h" +#include "qsv_memory.h" + +int qsv_nv12_to_yuv420(struct SwsContext* sws_context,hb_buffer_t* dst, mfxFrameSurface1* src, mfxCoreInterface *core){ + int ret = 0; + int i,j; + + int in_pitch = src->Data.Pitch; + int w = AV_QSV_ALIGN16(src->Info.Width); + int h = (MFX_PICSTRUCT_PROGRESSIVE == src->Info.PicStruct) ? AV_QSV_ALIGN16(src->Info.Height) : AV_QSV_ALIGN32(src->Info.Height); + uint8_t *in_luma = 0; + uint8_t *in_chroma = 0; + static int copyframe_in_use = 1; + + + mfxStatus sts = MFX_ERR_NONE; + mfxFrameSurface1 accel_dst; + + if (copyframe_in_use) + { + accel_dst.Info.FourCC = src->Info.FourCC; + accel_dst.Info.CropH = src->Info.CropH; + accel_dst.Info.CropW = src->Info.CropW; + accel_dst.Info.CropY = src->Info.CropY; + accel_dst.Info.CropX = src->Info.CropX; + accel_dst.Info.Width = w; + accel_dst.Info.Height = h; + accel_dst.Data.Pitch = src->Data.Pitch; + accel_dst.Data.Y = calloc( 1, in_pitch*h ); + accel_dst.Data.VU = calloc( 1, in_pitch*h/2 ); + + sts = core->CopyFrame(core->pthis, &accel_dst, src); + + if (sts < MFX_ERR_NONE) + { + free(accel_dst.Data.Y); + free(accel_dst.Data.VU); + copyframe_in_use = 0; + } + else + { + in_luma = accel_dst.Data.Y + accel_dst.Info.CropY * in_pitch + accel_dst.Info.CropX; + in_chroma = accel_dst.Data.VU + accel_dst.Info.CropY / 2 * in_pitch + accel_dst.Info.CropX; + } + } + + if (!copyframe_in_use) + { + in_luma = src->Data.Y + src->Info.CropY * in_pitch + src->Info.CropX; + in_chroma = src->Data.VU + src->Info.CropY / 2 * in_pitch + src->Info.CropX; + } + + hb_video_buffer_realloc( dst, w, h ); + + uint8_t *srcs[] = { in_luma, in_chroma }; + int srcs_stride[] = { in_pitch, in_pitch }; + + uint8_t *dsts[] = { dst->plane[0].data, dst->plane[1].data, dst->plane[2].data }; + int dsts_stride[] = { dst->plane[0].stride, dst->plane[1].stride, dst->plane[2].stride }; + + ret = sws_scale(sws_context, srcs, srcs_stride, 0, h, dsts, dsts_stride ); + + if (copyframe_in_use) + { + free(accel_dst.Data.Y); + free(accel_dst.Data.VU); + } + + return ret; +} + +int qsv_yuv420_to_nv12(struct SwsContext* sws_context,mfxFrameSurface1* dst, hb_buffer_t* src){ + int ret = 0; + + int w = src->plane[0].width; + int h = src->plane[0].height; + + int out_pitch = dst->Data.Pitch; + uint8_t *out_luma = dst->Data.Y; + uint8_t *out_chroma = dst->Data.VU; + + uint8_t *srcs[] = { src->plane[0].data, src->plane[1].data, src->plane[2].data }; + int srcs_stride[] = { src->plane[0].stride, src->plane[1].stride, src->plane[2].stride }; + + uint8_t *dsts[] = { out_luma, out_chroma }; + int dsts_stride[] = { out_pitch, out_pitch }; + + ret = sws_scale(sws_context, srcs, srcs_stride, 0, h, dsts, dsts_stride ); + + return ret; +} diff --git a/libhb/qsv_memory.h b/libhb/qsv_memory.h new file mode 100644 index 000000000..2d0f51208 --- /dev/null +++ b/libhb/qsv_memory.h @@ -0,0 +1,55 @@ +/* ********************************************************************* *\ + +Copyright (C) 2013 Intel Corporation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. +- Neither the name of Intel Corporation nor the names of its contributors +may be used to endorse or promote products derived from this software +without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +\* ********************************************************************* */ + +#ifndef QSV_MEMORY_H +#define QSV_MEMORY_H + +#include "libavcodec/qsv.h" +#include "msdk/mfxplugin.h" + +typedef struct{ + + struct{ + // for "planes" , Y and VU + uint8_t *data[2]; + int strides[2]; + } qsv_data; + + struct{ + // for each plane, Y U V + uint8_t *data[3]; + int strides[3]; + } data; + int width; + int height; +} qsv_memory_copy_t; + +int qsv_nv12_to_yuv420(struct SwsContext* sws_context,hb_buffer_t* dst, mfxFrameSurface1* src,mfxCoreInterface *core); +int qsv_yuv420_to_nv12(struct SwsContext* sws_context,mfxFrameSurface1* dst, hb_buffer_t* src); + +#endif // QSV_MEMORY_H diff --git a/libhb/reader.c b/libhb/reader.c index 83e6e513f..a7405fed7 100644 --- a/libhb/reader.c +++ b/libhb/reader.c @@ -535,8 +535,8 @@ void ReadLoop( void * _w ) else if ( buf->s.start >= r->job->pts_to_start ) { r->job->pts_to_start = 0; - r->start_found = 1; } + r->start_found = 1; } } diff --git a/libhb/scan.c b/libhb/scan.c index 0d7dde7ff..507662f36 100644 --- a/libhb/scan.c +++ b/libhb/scan.c @@ -865,6 +865,10 @@ skip_preview: title->color_transfer = vid_info.color_transfer; title->color_matrix = vid_info.color_matrix; +#ifdef USE_QSV + title->qsv_decode_support = vid_info.qsv_decode_support; +#endif + // compute the aspect ratio based on the storage dimensions and the // pixel aspect ratio (if supplied) or just storage dimensions if no PAR. title->aspect = (double)title->width / (double)title->height; diff --git a/libhb/sync.c b/libhb/sync.c index 3e88c40e5..8134688b3 100644 --- a/libhb/sync.c +++ b/libhb/sync.c @@ -55,6 +55,14 @@ typedef struct typedef struct { + int link; + int merge; + hb_buffer_t * list_current; + hb_buffer_t * last; +} subtitle_sanitizer_t; + +typedef struct +{ /* Video */ int first_frame; int64_t pts_skip; @@ -68,6 +76,8 @@ typedef struct int chap_mark; /* to propagate chapter mark across a drop */ hb_buffer_t * cur; /* The next picture to process */ + subtitle_sanitizer_t *subtitle_sanitizer; + /* Statistics */ uint64_t st_counts[4]; uint64_t st_dates[4]; @@ -91,6 +101,7 @@ struct hb_work_private_s static void getPtsOffset( hb_work_object_t * w ); static int checkPtsOffset( hb_work_object_t * w ); static void InitAudio( hb_job_t * job, hb_sync_common_t * common, int i ); +static void InitSubtitle( hb_job_t * job, hb_sync_video_t * sync, int i ); static void InsertSilence( hb_work_object_t * w, int64_t d ); static void UpdateState( hb_work_object_t * w ); static void UpdateSearchState( hb_work_object_t * w, int64_t start ); @@ -188,9 +199,34 @@ hb_work_object_t * hb_sync_init( hb_job_t * job ) for ( i = 0; i < pv->common->pts_count; i++ ) pv->common->first_pts[i] = INT64_MAX; + int count = hb_list_count(job->list_subtitle); + sync->subtitle_sanitizer = calloc(count, sizeof(subtitle_sanitizer_t)); + for( i = 0; i < count; i++ ) + { + InitSubtitle(job, sync, i); + } return ret; } +static void InitSubtitle( hb_job_t * job, hb_sync_video_t * sync, int i ) +{ + hb_subtitle_t * subtitle; + + subtitle = hb_list_item( job->list_subtitle, i ); + if (subtitle->format == TEXTSUB && + subtitle->config.dest == PASSTHRUSUB && + (job->mux & HB_MUX_MASK_MP4)) + { + // Merge overlapping subtitles since mpv tx3g does not support them + sync->subtitle_sanitizer[i].merge = 1; + } + if (subtitle->config.dest == PASSTHRUSUB) + { + // Fill in stop time when it is missing + sync->subtitle_sanitizer[i].link = 1; + } +} + /*********************************************************************** * Close Video *********************************************************************** @@ -248,6 +284,148 @@ void syncVideoClose( hb_work_object_t * w ) w->private_data = NULL; } +#define ABS(a) ((a) < 0 ? -(a) : (a)) + +static hb_buffer_t * mergeSubtitles(subtitle_sanitizer_t *sanitizer, int end) +{ + hb_buffer_t *a, *b, *buf, *out = NULL, *last = NULL; + + do + { + a = sanitizer->list_current; + + buf = NULL; + if (a != NULL && end) + { + sanitizer->list_current = a->next; + if (sanitizer->list_current == NULL) + sanitizer->last = NULL; + a->next = NULL; + buf = a; + } + else if (a != NULL && a->s.stop != -1) + { + b = a->next; + + if (b != NULL && !sanitizer->merge) + { + sanitizer->list_current = a->next; + if (sanitizer->list_current == NULL) + sanitizer->last = NULL; + a->next = NULL; + buf = a; + } + else if (b != NULL && a->s.stop > b->s.start) + { + // Overlap + if (ABS(a->s.start - b->s.start) <= 18000) + { + // subtitles start within 1/5 second of eachother, merge + sanitizer->list_current = a->next; + if (sanitizer->list_current == NULL) + sanitizer->last = NULL; + a->next = NULL; + b->s.start = a->s.stop; + + buf = hb_buffer_init(a->size + b->size); + buf->s = a->s; + sprintf((char*)buf->data, "%s\n%s", a->data, b->data); + hb_buffer_close(&a); + + if (b->s.stop != -1 && ABS(b->s.stop - b->s.start) <= 18000) + { + // b and a completely overlap, remove b + sanitizer->list_current = b->next; + if (sanitizer->list_current == NULL) + sanitizer->last = NULL; + hb_buffer_close(&b); + } + } + else + { + // a starts before b, output copy of a and + buf = hb_buffer_dup(a); + buf->s.stop = b->s.start; + a->s.start = b->s.start; + } + } + else if (b != NULL && a->s.stop <= b->s.start) + { + sanitizer->list_current = a->next; + if (sanitizer->list_current == NULL) + sanitizer->last = NULL; + a->next = NULL; + buf = a; + } + } + + if (buf != NULL) + { + if (buf->s.stop != -1) + buf->s.duration = buf->s.stop - buf->s.start; + else + buf->s.duration = -1; + if (last == NULL) + { + out = last = buf; + } + else + { + last->next = buf; + last = buf; + } + } + } while (buf != NULL); + + return out; +} + +static hb_buffer_t * sanitizeSubtitle( + hb_work_private_t * pv, + int i, + hb_buffer_t * sub) +{ + hb_sync_video_t * sync; + subtitle_sanitizer_t * sanitizer; + + sync = &pv->type.video; + sanitizer = &sync->subtitle_sanitizer[i]; + + if (!sanitizer->link && !sanitizer->merge) + { + return sub; + } + + if (sub == NULL) + { + return mergeSubtitles(sanitizer, 1); + } + + hb_lock( pv->common->mutex ); + sub->s.start -= pv->common->video_pts_slip; + if (sub->s.stop != -1) + sub->s.stop -= pv->common->video_pts_slip; + if (sub->s.renderOffset != -1) + sub->s.renderOffset -= pv->common->video_pts_slip; + hb_unlock( pv->common->mutex ); + + if (sanitizer->last != NULL && sanitizer->last->s.stop == -1) + { + sanitizer->last->s.stop = sub->s.start; + } + + if (sanitizer->last == NULL) + { + sanitizer->list_current = sanitizer->last = sub; + } + else + { + sanitizer->last->next = sub; + sanitizer->last = sub; + } + return mergeSubtitles(sanitizer, 0); +} + /*********************************************************************** * syncVideoWork *********************************************************************** @@ -273,7 +451,7 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in, { pv->common->first_pts[0] = next->s.start; hb_lock( pv->common->mutex ); - while( pv->common->pts_offset == INT64_MIN ) + while( pv->common->pts_offset == INT64_MIN && !*w->done ) { // Full fifos will make us wait forever, so get the // pts offset from the available streams if full @@ -337,12 +515,39 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in, } } hb_lock( pv->common->mutex ); - // Tell the audio threads what must be dropped - pv->common->audio_pts_thresh = next_start + pv->common->video_pts_slip; + if (job->frame_to_start > 0) + { + // When doing frame based p-to-p we must update the audio + // start point with each frame skipped. + // + // Tell the audio threads what must be dropped + pv->common->audio_pts_thresh = next->s.start; + } hb_cond_broadcast( pv->common->next_frame ); hb_unlock( pv->common->mutex ); UpdateSearchState( w, next_start ); +#ifdef USE_QSV + // reclaim QSV resources before dropping the buffer + // when decoding without QSV, the QSV atom will be NULL + if (job != NULL && job->qsv != NULL && next->qsv_details.qsv_atom != NULL) + { + av_qsv_stage *stage = av_qsv_get_last_stage(next->qsv_details.qsv_atom); + if (stage != NULL) + { + av_qsv_wait_on_sync(job->qsv, stage); + if (stage->out.sync->in_use > 0) + { + ff_qsv_atomic_dec(&stage->out.sync->in_use); + } + if (stage->out.p_surface->Data.Locked > 0) + { + ff_qsv_atomic_dec(&stage->out.p_surface->Data.Locked); + } + } + av_qsv_flush_stages(job->qsv->pipes, &next->qsv_details.qsv_atom); + } +#endif hb_buffer_close( &next ); return HB_WORK_OK; @@ -423,6 +628,10 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in, for( i = 0; i < hb_list_count( job->list_subtitle ); i++) { subtitle = hb_list_item( job->list_subtitle, i ); + // flush out any pending subtitle buffers in the sanitizer + hb_buffer_t *out = sanitizeSubtitle(pv, i, NULL); + if (out != NULL) + hb_fifo_push( subtitle->fifo_out, out ); if( subtitle->config.dest == PASSTHRUSUB ) { hb_fifo_push( subtitle->fifo_out, hb_buffer_init( 0 ) ); @@ -450,6 +659,10 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in, for( i = 0; i < hb_list_count( job->list_subtitle ); i++) { subtitle = hb_list_item( job->list_subtitle, i ); + // flush out any pending subtitle buffers in the sanitizer + hb_buffer_t *out = sanitizeSubtitle(pv, i, NULL); + if (out != NULL) + hb_fifo_push( subtitle->fifo_out, out ); if( subtitle->config.dest == PASSTHRUSUB ) { hb_fifo_push( subtitle->fifo_out, hb_buffer_init( 0 ) ); @@ -474,6 +687,10 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in, for( i = 0; i < hb_list_count( job->list_subtitle ); i++) { subtitle = hb_list_item( job->list_subtitle, i ); + // flush out any pending subtitle buffers in the sanitizer + hb_buffer_t *out = sanitizeSubtitle(pv, i, NULL); + if (out != NULL) + hb_fifo_push( subtitle->fifo_out, out ); if( subtitle->config.dest == PASSTHRUSUB ) { hb_fifo_push( subtitle->fifo_out, hb_buffer_init( 0 ) ); @@ -524,6 +741,29 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in, // don't drop a chapter mark when we drop the buffer sync->chap_mark = next->s.new_chap; } + +#ifdef USE_QSV + // reclaim QSV resources before dropping the buffer + // when decoding without QSV, the QSV atom will be NULL + if (job != NULL && job->qsv != NULL && next->qsv_details.qsv_atom != NULL) + { + av_qsv_stage *stage = av_qsv_get_last_stage(next->qsv_details.qsv_atom); + if (stage != NULL) + { + av_qsv_wait_on_sync(job->qsv, stage); + if (stage->out.sync->in_use > 0) + { + ff_qsv_atomic_dec(&stage->out.sync->in_use); + } + if (stage->out.p_surface->Data.Locked > 0) + { + ff_qsv_atomic_dec(&stage->out.p_surface->Data.Locked); + } + } + av_qsv_flush_stages(job->qsv->pipes, &next->qsv_details.qsv_atom); + } +#endif + hb_buffer_close( &next ); return HB_WORK_OK; } @@ -553,58 +793,20 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in, for( i = 0; i < hb_list_count( job->list_subtitle ); i++) { - int64_t sub_start, sub_stop, duration; + hb_buffer_t *out; subtitle = hb_list_item( job->list_subtitle, i ); // Sanitize subtitle start and stop times, then pass to // muxer or renderer filter. - while ( ( sub = hb_fifo_see( subtitle->fifo_raw ) ) != NULL ) + while ( ( sub = hb_fifo_get( subtitle->fifo_raw ) ) != NULL ) { - hb_lock( pv->common->mutex ); - sub_start = sub->s.start - pv->common->video_pts_slip; - hb_unlock( pv->common->mutex ); - - if (sub->s.stop == -1) - { - if (subtitle->config.dest != RENDERSUB && - hb_fifo_size( subtitle->fifo_raw ) < 2) - { - // For passthru subs, we want to wait for the - // next subtitle so that we can fill in the stop time. - // This way the muxer can compute the duration of - // the subtitle. - // - // For render subs, we need to ensure that they - // get to the renderer before the associated video - // that they are to be applied to. It is the - // responsibility of the renderer to handle - // stop == -1. - break; - } - } - - sub = hb_fifo_get( subtitle->fifo_raw ); - if ( sub->s.stop == -1 ) - { - hb_buffer_t *next; - next = hb_fifo_see( subtitle->fifo_raw ); - if (next != NULL) - sub->s.stop = next->s.start; - } - // Need to re-write subtitle timestamps to account - // for any slippage. - sub_stop = -1; - if ( sub->s.stop != -1 ) + if (sub->size > 0) { - duration = sub->s.stop - sub->s.start; - sub_stop = sub_start + duration; + out = sanitizeSubtitle(pv, i, sub); + if (out != NULL) + hb_fifo_push( subtitle->fifo_out, out ); } - - sub->s.start = sub_start; - sub->s.stop = sub_stop; - - hb_fifo_push( subtitle->fifo_out, sub ); } } @@ -626,6 +828,8 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in, sync->cur = cur = next; cur->sub = NULL; cur->s.start -= pv->common->video_pts_slip; + if (cur->s.renderOffset != -1) + cur->s.renderOffset -= pv->common->video_pts_slip; cur->s.stop -= pv->common->video_pts_slip; sync->pts_skip = 0; if ( duration <= 0 ) @@ -741,7 +945,7 @@ static int syncAudioWork( hb_work_object_t * w, hb_buffer_t ** buf_in, { pv->common->first_pts[sync->index+1] = buf->s.start; hb_lock( pv->common->mutex ); - while( pv->common->pts_offset == INT64_MIN ) + while( pv->common->pts_offset == INT64_MIN && !*w->done) { // Full fifos will make us wait forever, so get the // pts offset from the available streams if full @@ -758,10 +962,16 @@ static int syncAudioWork( hb_work_object_t * w, hb_buffer_t ** buf_in, hb_unlock( pv->common->mutex ); } - /* Wait for start frame if doing point-to-point */ + // Wait for start frame if doing point-to-point + // + // When doing p-to-p, video leads the way. The video thead will set + // start_found when we have reached the start point. + // + // When doing frame based p-to-p, as each video frame is processed + // it advances audio_pts_thresh which informs us how much audio must + // be dropped. hb_lock( pv->common->mutex ); - start = buf->s.start - pv->common->audio_pts_slip; - while ( !pv->common->start_found ) + while ( !pv->common->start_found && !*w->done ) { if ( pv->common->audio_pts_thresh < 0 ) { @@ -776,8 +986,14 @@ static int syncAudioWork( hb_work_object_t * w, hb_buffer_t ** buf_in, hb_unlock( pv->common->mutex ); return HB_WORK_OK; } + + // We should only get here when doing frame based p-to-p. + // In frame based p-to-p, the video sync thread updates + // audio_pts_thresh as it discards frames. So wait here + // until the current audio frame needs to be discarded + // or start point is found. while ( !pv->common->start_found && - buf->s.start >= pv->common->audio_pts_thresh ) + buf->s.start >= pv->common->audio_pts_thresh && !*w->done ) { hb_cond_timedwait( pv->common->next_frame, pv->common->mutex, 10 ); // There is an unfortunate unavoidable deadlock that can occur. @@ -804,15 +1020,20 @@ static int syncAudioWork( hb_work_object_t * w, hb_buffer_t ** buf_in, } } } - start = buf->s.start - pv->common->audio_pts_slip; } - if ( start < 0 ) + start = buf->s.start - pv->common->audio_pts_slip; + hb_unlock( pv->common->mutex ); + + // When doing p-to-p, video determines when the start point has been + // found. Since audio and video are processed asynchronously, there + // may yet be audio packets in the pipe that are before the start point. + // These packets will have negative start times after applying + // audio_pts_slip. + if (start < 0) { - hb_buffer_close( &buf ); - hb_unlock( pv->common->mutex ); + hb_buffer_close(&buf); return HB_WORK_OK; } - hb_unlock( pv->common->mutex ); if( job->frame_to_stop && pv->common->count_frames >= job->frame_to_stop ) { diff --git a/libhb/work.c b/libhb/work.c index b417594b8..d44f763be 100644 --- a/libhb/work.c +++ b/libhb/work.c @@ -12,6 +12,11 @@ #include "libavformat/avformat.h" #include "openclwrapper.h" +#ifdef USE_QSV +#include "qsv_common.h" +#include "qsv_filter_pp.h" +#endif + typedef struct { hb_list_t * jobs; @@ -214,6 +219,7 @@ void hb_display_job_info(hb_job_t *job) case HB_MUX_MP4V2: if (job->largeFileSize) hb_log(" + 64-bit chunk offsets"); + case HB_MUX_AV_MP4: if (job->mp4_optimize) hb_log(" + optimized for HTTP streaming (fast start)"); if (job->ipod_atom) @@ -231,8 +237,18 @@ void hb_display_job_info(hb_job_t *job) hb_log(" * video track"); - hb_log(" + decoder: %s", title->video_codec_name ); - +#ifdef USE_QSV + if (hb_qsv_decode_is_enabled(job)) + { + hb_log(" + decoder: %s", + hb_qsv_decode_get_codec_name(title->video_codec_param)); + } + else +#endif + { + hb_log(" + decoder: %s", title->video_codec_name); + } + if( title->video_bitrate ) { hb_log( " + bitrate %d kbps", title->video_bitrate / 1000 ); @@ -307,20 +323,21 @@ void hb_display_job_info(hb_job_t *job) { hb_log(" + options: %s", job->advanced_opts); } - if( job->h264_profile && *job->h264_profile && - job->vcodec == HB_VCODEC_X264 ) + if (job->h264_profile != NULL && *job->h264_profile && + (job->vcodec & HB_VCODEC_H264_MASK)) { - hb_log( " + h264 profile: %s", job->h264_profile ); + hb_log(" + h264 profile: %s", job->h264_profile); } - if( job->h264_level && *job->h264_level && - job->vcodec == HB_VCODEC_X264 ) + if (job->h264_level != NULL && *job->h264_level && + (job->vcodec & HB_VCODEC_H264_MASK)) { - hb_log( " + h264 level: %s", job->h264_level ); + hb_log(" + h264 level: %s", job->h264_level); } - if( job->vquality >= 0 ) + if (job->vquality >= 0) { - hb_log( " + quality: %.2f %s", job->vquality, job->vcodec == HB_VCODEC_X264 ? "(RF)" : "(QP)" ); + hb_log(" + quality: %.2f (%s)", job->vquality, + hb_video_quality_get_name(job->vcodec)); } else { @@ -674,6 +691,114 @@ static void do_job(hb_job_t *job) } } +#ifdef USE_QSV + /* + * When QSV is used for decoding, not all CPU-based filters are supported, + * so we need to do a little extra setup here. + */ + if (hb_qsv_decode_is_enabled(job)) + { + int vpp_settings[7]; + int num_cpu_filters = 0; + hb_filter_object_t *filter; + // default values for VPP filter + vpp_settings[0] = job->title->width; + vpp_settings[1] = job->title->height; + vpp_settings[2] = job->title->crop[0]; + vpp_settings[3] = job->title->crop[1]; + vpp_settings[4] = job->title->crop[2]; + vpp_settings[5] = job->title->crop[3]; + vpp_settings[6] = 0; // deinterlace: off + if (job->list_filter != NULL && hb_list_count(job->list_filter) > 0) + { + while (hb_list_count(job->list_filter) > num_cpu_filters) + { + filter = hb_list_item(job->list_filter, num_cpu_filters); + switch (filter->id) + { + // cropping and scaling always done via VPP filter + case HB_FILTER_CROP_SCALE: + if (filter->settings == NULL || *filter->settings == '\0') + { + // VPP defaults were set above, so not a problem + // however, this should never happen, print an error + hb_error("do_job: '%s': no settings!", filter->name); + } + else + { + sscanf(filter->settings, "%d:%d:%d:%d:%d:%d", + &vpp_settings[0], &vpp_settings[1], + &vpp_settings[2], &vpp_settings[3], + &vpp_settings[4], &vpp_settings[5]); + } + hb_list_rem(job->list_filter, filter); + hb_filter_close(&filter); + break; + + // pick VPP or CPU deinterlace depending on settings + case HB_FILTER_DEINTERLACE: + if (filter->settings == NULL || !strcmp(filter->settings, "qsv")) + { + // deinterlacing via VPP filter + vpp_settings[6] = 1; + hb_list_rem(job->list_filter, filter); + hb_filter_close(&filter); + } + else + { + // validated + num_cpu_filters++; + } + break; + + // then, validated filters + case HB_FILTER_ROTATE: // TODO: use Media SDK for this + case HB_FILTER_RENDER_SUB: + num_cpu_filters++; + break; + + // finally, drop all unsupported filters + default: + hb_log("do_job: full QSV path, removing unsupported filter '%s'", + filter->name); + hb_list_rem(job->list_filter, filter); + hb_filter_close(&filter); + break; + } + } + if (num_cpu_filters > 0) + { + // we need filters to copy to system memory and back + filter = hb_filter_init(HB_FILTER_QSV_PRE); + hb_add_filter(job, filter, NULL); + filter = hb_filter_init(HB_FILTER_QSV_POST); + hb_add_filter(job, filter, NULL); + } + if (vpp_settings[0] != job->title->width || + vpp_settings[1] != job->title->height || + vpp_settings[2] >= 1 /* crop */ || + vpp_settings[3] >= 1 /* crop */ || + vpp_settings[4] >= 1 /* crop */ || + vpp_settings[5] >= 1 /* crop */ || + vpp_settings[6] >= 1 /* deinterlace */) + { + // we need the VPP filter + char *settings = hb_strdup_printf("%d:%d:%d:%d:%d:%d_dei:%d", + vpp_settings[0], + vpp_settings[1], + vpp_settings[2], + vpp_settings[3], + vpp_settings[4], + vpp_settings[5], + vpp_settings[6]); + filter = hb_filter_init(HB_FILTER_QSV); + hb_add_filter(job, filter, settings); + free(settings); + } + } + } +#endif + // Filters have an effect on settings. // So initialize the filters and update the job. if( job->list_filter && hb_list_count( job->list_filter ) ) @@ -738,12 +863,25 @@ static void do_job(hb_job_t *job) } } } - - job->fifo_mpeg2 = hb_fifo_init( FIFO_LARGE, FIFO_LARGE_WAKE ); - job->fifo_raw = hb_fifo_init( FIFO_SMALL, FIFO_SMALL_WAKE ); - job->fifo_sync = hb_fifo_init( FIFO_SMALL, FIFO_SMALL_WAKE ); - job->fifo_mpeg4 = hb_fifo_init( FIFO_LARGE, FIFO_LARGE_WAKE ); - job->fifo_render = NULL; // Attached to filter chain + +#ifdef USE_QSV + if (hb_qsv_decode_is_enabled(job)) + { + job->fifo_mpeg2 = hb_fifo_init( FIFO_MINI, FIFO_MINI_WAKE ); + job->fifo_raw = hb_fifo_init( FIFO_MINI, FIFO_MINI_WAKE ); + job->fifo_sync = hb_fifo_init( FIFO_MINI, FIFO_MINI_WAKE ); + job->fifo_render = hb_fifo_init( FIFO_MINI, FIFO_MINI_WAKE ); + job->fifo_mpeg4 = hb_fifo_init( FIFO_MINI, FIFO_MINI_WAKE ); + } + else +#endif + { + job->fifo_mpeg2 = hb_fifo_init( FIFO_LARGE, FIFO_LARGE_WAKE ); + job->fifo_raw = hb_fifo_init( FIFO_SMALL, FIFO_SMALL_WAKE ); + job->fifo_sync = hb_fifo_init( FIFO_SMALL, FIFO_SMALL_WAKE ); + job->fifo_mpeg4 = hb_fifo_init( FIFO_LARGE, FIFO_LARGE_WAKE ); + job->fifo_render = NULL; // Attached to filter chain + } /* Audio fifos must be initialized before sync */ if (!job->indepth_scan) @@ -1047,6 +1185,9 @@ static void do_job(hb_job_t *job) case HB_VCODEC_X264: w = hb_get_work( WORK_ENCX264 ); break; + case HB_VCODEC_QSV_H264: + w = hb_get_work( WORK_ENCQSV ); + break; case HB_VCODEC_THEORA: w = hb_get_work( WORK_ENCTHEORA ); break; @@ -1542,8 +1683,27 @@ static void filter_loop( void * _f ) } buf_out = NULL; + +#ifdef USE_QSV + hb_buffer_t *last_buf_in = buf_in; +#endif + f->status = f->work( f, &buf_in, &buf_out ); +#ifdef USE_QSV + if (f->status == HB_FILTER_DELAY && + last_buf_in->qsv_details.filter_details != NULL && buf_out == NULL) + { + hb_filter_private_t_qsv *qsv_user = buf_in ? buf_in->qsv_details.filter_details : last_buf_in->qsv_details.filter_details ; + qsv_user->post.status = f->status; + + hb_lock(qsv_user->post.frame_completed_lock); + qsv_user->post.frame_go = 1; + hb_cond_broadcast(qsv_user->post.frame_completed); + hb_unlock(qsv_user->post.frame_completed_lock); + + } +#endif if ( buf_out && f->chapter_val && f->chapter_time <= buf_out->s.start ) { buf_out->s.new_chap = f->chapter_val; diff --git a/macosx/ChapterTitles.m b/macosx/ChapterTitles.m index d568af8a4..1ff8b1194 100644 --- a/macosx/ChapterTitles.m +++ b/macosx/ChapterTitles.m @@ -41,7 +41,8 @@ if (chapter->title != NULL) { [fChapterTitlesArray addObject:[NSString - stringWithUTF8String:chapter->title]]; + stringWithFormat:@"%s", + chapter->title]]; } else { diff --git a/macosx/Controller.h b/macosx/Controller.h index 6020f64f8..607960f6d 100644 --- a/macosx/Controller.h +++ b/macosx/Controller.h @@ -214,6 +214,7 @@ BOOL fIsDragging; BOOL fRipIndicatorShown; /* Queue File variables */ + FSEventStreamRef QueueStream; NSString * QueueFile; NSMutableArray * QueueFileArray; int currentQueueEncodeIndex; // Used to track the currently encoding queueu item @@ -356,7 +357,10 @@ BOOL fIsDragging; - (void) doAddAllTitlesToQueue; /* Queue File Stuff */ +- (void) initQueueFSEvent; +- (void) closeQueueFSEvent; - (void) loadQueueFile; +- (void) reloadQueue; - (NSDictionary *)createQueueFileItem; - (void)saveQueueFileItem; - (void) incrementQueueItemDone:(int) queueItemDoneIndexNum; diff --git a/macosx/Controller.m b/macosx/Controller.m index d5dd32bff..1dca55413 100644 --- a/macosx/Controller.m +++ b/macosx/Controller.m @@ -46,6 +46,23 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It + (unsigned int) maximumNumberOfAllowedAudioTracks { return maximumNumberOfAllowedAudioTracks; } +- (NSString *)appSupportPath +{ + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSString *appSupportPath = nil; + + NSArray *allPaths = NSSearchPathForDirectoriesInDomains( NSApplicationSupportDirectory, + NSUserDomainMask, + YES ); + if( [allPaths count] ) + appSupportPath = [[allPaths objectAtIndex:0] stringByAppendingPathComponent:@"HandBrake"]; + + if( ![fileManager fileExistsAtPath:appSupportPath] ) + [fileManager createDirectoryAtPath:appSupportPath withIntermediateDirectories:YES attributes:nil error:NULL]; + + return appSupportPath; +} + - (id)init { self = [super init]; @@ -65,16 +82,7 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It /* Check for check for the app support directory here as * outputPanel needs it right away, as may other future methods */ - NSString *libraryDir = [NSSearchPathForDirectoriesInDomains( NSLibraryDirectory, - NSUserDomainMask, - YES ) objectAtIndex:0]; - AppSupportDirectory = [[libraryDir stringByAppendingPathComponent:@"Application Support"] - stringByAppendingPathComponent:@"HandBrake"]; - if( ![[NSFileManager defaultManager] fileExistsAtPath:AppSupportDirectory] ) - { - [[NSFileManager defaultManager] createDirectoryAtPath:AppSupportDirectory - attributes:nil]; - } + AppSupportDirectory = [self appSupportPath]; /* Check for and create the App Support Preview directory if necessary */ NSString *PreviewDirectory = [AppSupportDirectory stringByAppendingPathComponent:@"Previews"]; if( ![[NSFileManager defaultManager] fileExistsAtPath:PreviewDirectory] ) @@ -225,6 +233,7 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It /* Init QueueFile .plist */ [self loadQueueFile]; + [self initQueueFSEvent]; /* Run hbInstances to get any info on other instances as well as set the * pid number for this instance in the case of multi-instance encoding. */ hbInstanceNum = [self hbInstances]; @@ -523,6 +532,7 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It [self setQueueEncodingItemsAsPending]; } + [self reloadQueue]; [self showQueueWindow:NULL]; } } @@ -572,6 +582,7 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It // it's highly probable that the user throw a lot of files and just want to reset this [[NSUserDefaults standardUserDefaults] removeObjectForKey:dragDropFiles]; + [self closeQueueFSEvent]; [currentQueueEncodeNameString release]; [browsedSourceDisplayName release]; [outputPanel release]; @@ -1231,17 +1242,9 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It break; } } - - /* Since we can use multiple instance off of the same queue file it is imperative that we keep the QueueFileArray updated off of the QueueFile.plist - * so we go ahead and do it in this existing timer as opposed to using a new one */ - - NSMutableArray * tempQueueArray = [[NSMutableArray alloc] initWithContentsOfFile:QueueFile]; - [QueueFileArray setArray:tempQueueArray]; - [tempQueueArray release]; - /* Send Fresh QueueFileArray to fQueueController to update queue window */ - [fQueueController setQueueArray: QueueFileArray]; + [self getQueueStats]; - + /* Update the visibility of the Auto Passthru advanced options box */ if ([[NSUserDefaults standardUserDefaults] boolForKey:@"ShowAdvancedOptsForAutoPassthru"] == YES) { @@ -1999,16 +2002,22 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It { /* User chose to override our warning and scan the physical dvd anyway, at their own peril. on an encrypted dvd this produces massive log files and fails */ cancelScanDecrypt = 0; - [self writeToActivityLog: "User overrode copy-proteciton warning - trying to open physical dvd without decryption"]; + [self writeToActivityLog:"User overrode copy-protection warning - trying to open physical dvd without decryption"]; } } - else + else if (dvdcss != NULL) { /* VLC was found in /Applications so all is well, we can carry on using vlc's libdvdcss.dylib for decrypting if needed */ [self writeToActivityLog: "libdvdcss.2.dylib found for decrypting physical dvd"]; dlclose(dvdcss); } + else + { + /* User chose to override our warning and scan the physical dvd anyway, at their own peril. on an encrypted dvd this produces massive log files and fails */ + cancelScanDecrypt = 0; + [self writeToActivityLog:"Copy-protection warning disabled in preferences - trying to open physical dvd without decryption"]; + } } if (cancelScanDecrypt == 0) @@ -2277,21 +2286,80 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It #pragma mark - #pragma mark Queue File -- (void) loadQueueFile { +static void queueFSEventStreamCallback( + ConstFSEventStreamRef streamRef, + void *clientCallBackInfo, + size_t numEvents, + void *eventPaths, + const FSEventStreamEventFlags eventFlags[], + const FSEventStreamEventId eventIds[]) +{ + HBController *hb = (HBController *)clientCallBackInfo; + [hb reloadQueue]; +} + +- (void)initQueueFSEvent +{ + /* Define variables and create a CFArray object containing + CFString objects containing paths to watch. + */ + CFStringRef mypath = (CFStringRef) [[self appSupportPath] stringByAppendingPathComponent:@"Queue"]; + CFArrayRef pathsToWatch = CFArrayCreate(NULL, (const void **)&mypath, 1, NULL); + + FSEventStreamContext callbackCtx; + callbackCtx.version = 0; + callbackCtx.info = self; + callbackCtx.retain = NULL; + callbackCtx.release = NULL; + callbackCtx.copyDescription = NULL; + + CFAbsoluteTime latency = 0.5; /* Latency in seconds */ + + /* Create the stream, passing in a callback */ + QueueStream = FSEventStreamCreate(NULL, + &queueFSEventStreamCallback, + &callbackCtx, + pathsToWatch, + kFSEventStreamEventIdSinceNow, + latency, + kFSEventStreamCreateFlagIgnoreSelf + ); + + /* Create the stream before calling this. */ + FSEventStreamScheduleWithRunLoop(QueueStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + FSEventStreamStart(QueueStream); +} + +- (void)closeQueueFSEvent +{ + FSEventStreamStop(QueueStream); + FSEventStreamInvalidate(QueueStream); + FSEventStreamRelease(QueueStream); +} + +- (void)loadQueueFile +{ /* We declare the default NSFileManager into fileManager */ - NSFileManager * fileManager = [NSFileManager defaultManager]; + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSString *appSupportPath = [self appSupportPath]; + /* We define the location of the user presets file */ - QueueFile = @"~/Library/Application Support/HandBrake/Queue.plist"; - QueueFile = [[QueueFile stringByExpandingTildeInPath]retain]; + QueueFile = [[appSupportPath stringByAppendingPathComponent:@"Queue/Queue.plist"] retain]; + /* We check for the Queue.plist */ - if ([fileManager fileExistsAtPath:QueueFile] == 0) + if( ![fileManager fileExistsAtPath:QueueFile] ) { + if( ![fileManager fileExistsAtPath:[appSupportPath stringByAppendingPathComponent:@"Queue"]] ) + { + [fileManager createDirectoryAtPath:[appSupportPath stringByAppendingPathComponent:@"Queue"] withIntermediateDirectories:YES attributes:nil error:NULL]; + } + [fileManager createFileAtPath:QueueFile contents:nil attributes:nil]; } - + QueueFileArray = [[NSMutableArray alloc] initWithContentsOfFile:QueueFile]; /* lets check to see if there is anything in the queue file .plist */ - if (nil == QueueFileArray) + if( QueueFileArray == nil ) { /* if not, then lets initialize an empty array */ QueueFileArray = [[NSMutableArray alloc] init]; @@ -2299,13 +2367,24 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It else { /* ONLY clear out encoded items if we are single instance */ - if (hbInstanceNum == 1) + if( hbInstanceNum == 1 ) { [self clearQueueEncodedItems]; } } } +- (void)reloadQueue +{ + [self writeToActivityLog:"Queue reloaded"]; + + NSMutableArray * tempQueueArray = [[NSMutableArray alloc] initWithContentsOfFile:QueueFile]; + [QueueFileArray setArray:tempQueueArray]; + [tempQueueArray release]; + /* Send Fresh QueueFileArray to fQueueController to update queue window */ + [fQueueController setQueueArray: QueueFileArray]; +} + - (void)addQueueFileItem { [QueueFileArray addObject:[self createQueueFileItem]]; @@ -3056,15 +3135,23 @@ fWorkingCount = 0; [fVidBitrateField setStringValue:[queueToApply objectForKey:@"VideoAvgBitrate"]]; - if ([[fVidEncoderPopUp selectedItem] tag] == HB_VCODEC_THEORA) + int direction; + float minValue, maxValue, granularity; + hb_video_quality_get_limits([[fVidEncoderPopUp selectedItem] tag], + &minValue, &maxValue, &granularity, &direction); + if (!direction) { - /* Since theora's qp value goes up from left to right, we can just set the slider float value */ [fVidQualitySlider setFloatValue:[[queueToApply objectForKey:@"VideoQualitySlider"] floatValue]]; } else { - /* Since ffmpeg and x264 use an "inverted" slider (lower qp/rf values indicate a higher quality) we invert the value on the slider */ - [fVidQualitySlider setFloatValue:([fVidQualitySlider maxValue] + [fVidQualitySlider minValue]) - [[queueToApply objectForKey:@"VideoQualitySlider"] floatValue]]; + /* + * Since ffmpeg and x264 use an "inverted" slider (lower values + * indicate a higher quality) we invert the value on the slider + */ + [fVidQualitySlider setFloatValue:([fVidQualitySlider minValue] + + [fVidQualitySlider maxValue] - + [[queueToApply objectForKey:@"VideoQualitySlider"] floatValue])]; } [self videoMatrixChanged:nil]; @@ -4894,8 +4981,8 @@ bool one_burned = FALSE; //[self calculateBitrate: sender]; /* We're changing the chapter range - we may need to flip the m4v/mp4 extension */ - if ([fDstFormatPopUp indexOfSelectedItem] == 0) - [self autoSetM4vExtension: sender]; + if ([[fDstFormatPopUp selectedItem] tag] & HB_MUX_MASK_MP4) + [self autoSetM4vExtension:sender]; } - (IBAction) startEndSecValueChanged: (id) sender @@ -5008,6 +5095,7 @@ bool one_burned = FALSE; { case HB_MUX_MP4V2: [fDstMp4LargeFileCheck setHidden:NO]; + case HB_MUX_AV_MP4: [fDstMp4HttpOptFileCheck setHidden:NO]; [fDstMp4iPodFileCheck setHidden:NO]; break; @@ -5051,7 +5139,7 @@ bool one_burned = FALSE; - (IBAction) autoSetM4vExtension: (id) sender { - if ( [fDstFormatPopUp indexOfSelectedItem] ) + if (!([[fDstFormatPopUp selectedItem] tag] & HB_MUX_MASK_MP4)) return; NSString * extension = @"mp4"; @@ -5253,43 +5341,44 @@ the user is using "Custom" settings by determining the sender*/ */ - (void) setupQualitySlider { - /* Get the current slider maxValue to check for a change in slider scale later - * so that we can choose a new similar value on the new slider scale */ - float previousMaxValue = [fVidQualitySlider maxValue]; - float previousPercentOfSliderScale = [fVidQualitySlider floatValue] / ([fVidQualitySlider maxValue] - [fVidQualitySlider minValue] + 1); - NSString * qpRFLabelString = @"QP:"; - /* x264 0-51 */ + /* + * Get the current slider maxValue to check for a change in slider scale + * later so that we can choose a new similar value on the new slider scale + */ + float previousMaxValue = [fVidQualitySlider maxValue]; + float previousPercentOfSliderScale = ([fVidQualitySlider floatValue] / + ([fVidQualitySlider maxValue] - + [fVidQualitySlider minValue] + 1)); + [fVidQualityRFLabel setStringValue:[NSString stringWithFormat:@"%s", + hb_video_quality_get_name([[fVidEncoderPopUp + selectedItem] tag])]]; + int direction; + float minValue, maxValue, granularity; + hb_video_quality_get_limits([[fVidEncoderPopUp selectedItem] tag], + &minValue, &maxValue, &granularity, &direction); if ([[fVidEncoderPopUp selectedItem] tag] == HB_VCODEC_X264) { - [fVidQualitySlider setMinValue:0.0]; - [fVidQualitySlider setMaxValue:51.0]; - /* As x264 allows for qp/rf values that are fractional, we get the value from the preferences */ - int fractionalGranularity = 1 / [[NSUserDefaults standardUserDefaults] floatForKey:@"x264CqSliderFractional"]; - [fVidQualitySlider setNumberOfTickMarks:(([fVidQualitySlider maxValue] - [fVidQualitySlider minValue]) * fractionalGranularity) + 1]; - qpRFLabelString = @"RF:"; - } - /* FFmpeg MPEG-2/4 1-31 */ - if ([[fVidEncoderPopUp selectedItem] tag] & HB_VCODEC_FFMPEG_MASK ) - { - [fVidQualitySlider setMinValue:1.0]; - [fVidQualitySlider setMaxValue:31.0]; - [fVidQualitySlider setNumberOfTickMarks:31]; - } - /* Theora 0-63 */ - if ([[fVidEncoderPopUp selectedItem] tag] == HB_VCODEC_THEORA) - { - [fVidQualitySlider setMinValue:0.0]; - [fVidQualitySlider setMaxValue:63.0]; - [fVidQualitySlider setNumberOfTickMarks:64]; + /* + * As x264 allows for qp/rf values that are fractional, + * we get the value from the preferences + */ + granularity = [[NSUserDefaults standardUserDefaults] + floatForKey:@"x264CqSliderFractional"]; } - [fVidQualityRFLabel setStringValue:qpRFLabelString]; + [fVidQualitySlider setMinValue:minValue]; + [fVidQualitySlider setMaxValue:maxValue]; + [fVidQualitySlider setNumberOfTickMarks:((maxValue - minValue) * + (1. / granularity)) + 1]; /* check to see if we have changed slider scales */ - if (previousMaxValue != [fVidQualitySlider maxValue]) + if (previousMaxValue != maxValue) { - /* if so, convert the old setting to the new scale as close as possible based on percentages */ - float rf = ([fVidQualitySlider maxValue] - [fVidQualitySlider minValue] + 1) * previousPercentOfSliderScale; - [fVidQualitySlider setFloatValue:rf]; + /* + * if so, convert the old setting to the new scale as close as possible + * based on percentages + */ + [fVidQualitySlider setFloatValue:((maxValue - minValue + 1.) * + (previousPercentOfSliderScale))]; } [self qualitySliderChanged:nil]; @@ -5297,8 +5386,8 @@ the user is using "Custom" settings by determining the sender*/ - (IBAction) qualitySliderChanged: (id) sender { - - /* Our constant quality slider is in a range based + /* + * Our constant quality slider is in a range based * on each encoders qp/rf values. The range depends * on the encoder. Also, the range is inverse of quality * for all of the encoders *except* for theora @@ -5310,22 +5399,28 @@ the user is using "Custom" settings by determining the sender*/ * so, the floatValue at the right for x264 would be 51 * and our rf field needs to show 0 and vice versa. */ - - float sliderRfInverse = ([fVidQualitySlider maxValue] - [fVidQualitySlider floatValue]) + [fVidQualitySlider minValue]; - /* If the encoder is theora, use the float, otherwise use the inverse float*/ - //float sliderRfToPercent; - if ([[fVidEncoderPopUp selectedItem] tag] == HB_VCODEC_THEORA) - { - [fVidQualityRFField setStringValue: [NSString stringWithFormat: @"%.2f", [fVidQualitySlider floatValue]]]; + int direction; + float minValue, maxValue, granularity; + float inverseValue = ([fVidQualitySlider minValue] + + [fVidQualitySlider maxValue] - + [fVidQualitySlider floatValue]); + hb_video_quality_get_limits([[fVidEncoderPopUp selectedItem] tag], + &minValue, &maxValue, &granularity, &direction); + if (!direction) + { + [fVidQualityRFField setStringValue:[NSString stringWithFormat:@"%.2f", + [fVidQualitySlider floatValue]]]; } else { - [fVidQualityRFField setStringValue: [NSString stringWithFormat: @"%.2f", sliderRfInverse]]; + [fVidQualityRFField setStringValue:[NSString stringWithFormat:@"%.2f", + inverseValue]]; } /* Show a warning if x264 and rf 0 which is lossless */ - if ([[fVidEncoderPopUp selectedItem] tag] == HB_VCODEC_X264 && sliderRfInverse == 0.0) + if ([[fVidEncoderPopUp selectedItem] tag] == HB_VCODEC_X264 && inverseValue == 0.0) { - [fVidQualityRFField setStringValue: [NSString stringWithFormat: @"%.2f (Warning: Lossless)", sliderRfInverse]]; + [fVidQualityRFField setStringValue:[NSString stringWithFormat:@"%.2f (Warning: Lossless)", + inverseValue]]; } [self customSettingUsed: sender]; @@ -6537,15 +6632,23 @@ return YES; [fVidBitrateField setStringValue:[chosenPreset objectForKey:@"VideoAvgBitrate"]]; - if ([[fVidEncoderPopUp selectedItem] tag] == HB_VCODEC_THEORA) + int direction; + float minValue, maxValue, granularity; + hb_video_quality_get_limits([[fVidEncoderPopUp selectedItem] tag], + &minValue, &maxValue, &granularity, &direction); + if (!direction) { - /* Since theora's qp value goes up from left to right, we can just set the slider float value */ [fVidQualitySlider setFloatValue:[[chosenPreset objectForKey:@"VideoQualitySlider"] floatValue]]; } else { - /* Since ffmpeg and x264 use an "inverted" slider (lower qp/rf values indicate a higher quality) we invert the value on the slider */ - [fVidQualitySlider setFloatValue:([fVidQualitySlider maxValue] + [fVidQualitySlider minValue]) - [[chosenPreset objectForKey:@"VideoQualitySlider"] floatValue]]; + /* + * Since ffmpeg and x264 use an "inverted" slider (lower values + * indicate a higher quality) we invert the value on the slider + */ + [fVidQualitySlider setFloatValue:([fVidQualitySlider minValue] + + [fVidQualitySlider maxValue] - + [[chosenPreset objectForKey:@"VideoQualitySlider"] floatValue])]; } [self videoMatrixChanged:nil]; diff --git a/macosx/English.lproj/Preferences.xib b/macosx/English.lproj/Preferences.xib index ab9a908bf..405e613fd 100644 --- a/macosx/English.lproj/Preferences.xib +++ b/macosx/English.lproj/Preferences.xib @@ -2,31 +2,31 @@ <archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10"> <data> <int key="IBDocument.SystemTarget">1050</int> - <string key="IBDocument.SystemVersion">11G63</string> - <string key="IBDocument.InterfaceBuilderVersion">1938</string> - <string key="IBDocument.AppKitVersion">1138.51</string> - <string key="IBDocument.HIToolboxVersion">569.00</string> + <string key="IBDocument.SystemVersion">12D78</string> + <string key="IBDocument.InterfaceBuilderVersion">3084</string> + <string key="IBDocument.AppKitVersion">1187.37</string> + <string key="IBDocument.HIToolboxVersion">626.00</string> <object class="NSMutableDictionary" key="IBDocument.PluginVersions"> <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="NS.object.0">1938</string> + <string key="NS.object.0">3084</string> </object> <object class="NSArray" key="IBDocument.IntegratedClassDependencies"> <bool key="EncodedWithXMLCoder">YES</bool> - <string>NSPopUpButtonCell</string> - <string>NSComboBoxCell</string> - <string>NSPopUpButton</string> <string>NSButton</string> - <string>NSMenu</string> - <string>NSTextFieldCell</string> <string>NSButtonCell</string> - <string>NSMenuItem</string> <string>NSComboBox</string> - <string>NSCustomView</string> + <string>NSComboBoxCell</string> <string>NSCustomObject</string> - <string>NSView</string> - <string>NSWindowTemplate</string> + <string>NSCustomView</string> + <string>NSMenu</string> + <string>NSMenuItem</string> + <string>NSPopUpButton</string> + <string>NSPopUpButtonCell</string> <string>NSTextField</string> + <string>NSTextFieldCell</string> <string>NSUserDefaultsController</string> + <string>NSView</string> + <string>NSWindowTemplate</string> </object> <object class="NSArray" key="IBDocument.PluginDependencies"> <bool key="EncodedWithXMLCoder">YES</bool> @@ -64,8 +64,6 @@ <int key="NSvFlags">256</int> <string key="NSFrameSize">{500, 200}</string> <reference key="NSSuperview"/> - <reference key="NSWindow"/> - <reference key="NSNextKeyView"/> </object> <string key="NSScreenRect">{{0, 0}, {1440, 878}}</string> <string key="NSMinSize">{213, 129}</string> @@ -76,7 +74,7 @@ <bool key="NSSharedInstance">YES</bool> </object> <object class="NSCustomView" id="1048779201"> - <nil key="NSNextResponder"/> + <reference key="NSNextResponder"/> <int key="NSvFlags">256</int> <object class="NSMutableArray" key="NSSubviews"> <bool key="EncodedWithXMLCoder">YES</bool> @@ -88,7 +86,7 @@ <reference key="NSNextKeyView" ref="1009109497"/> <bool key="NSEnabled">YES</bool> <object class="NSPopUpButtonCell" key="NSCell" id="630285587"> - <int key="NSCellFlags">-2076049856</int> + <int key="NSCellFlags">-2076180416</int> <int key="NSCellFlags2">133120</int> <object class="NSFont" key="NSSupport" id="26"> <string key="NSName">LucidaGrande</string> @@ -96,7 +94,7 @@ <int key="NSfFlags">3100</int> </object> <reference key="NSControlView" ref="23412822"/> - <int key="NSButtonFlags">109199615</int> + <int key="NSButtonFlags">109199360</int> <int key="NSButtonFlags2">129</int> <string key="NSAlternateContents"/> <string key="NSKeyEquivalent"/> @@ -194,6 +192,7 @@ <bool key="NSAltersState">YES</bool> <int key="NSArrowPosition">2</int> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSButton" id="1009109497"> <reference key="NSNextResponder" ref="1048779201"/> @@ -203,12 +202,12 @@ <reference key="NSNextKeyView" ref="597305137"/> <bool key="NSEnabled">YES</bool> <object class="NSButtonCell" key="NSCell" id="878201725"> - <int key="NSCellFlags">-2080244224</int> + <int key="NSCellFlags">-2080374784</int> <int key="NSCellFlags2">131072</int> <string key="NSContents">Play System Alert Sound</string> <reference key="NSSupport" ref="26"/> <reference key="NSControlView" ref="1009109497"/> - <int key="NSButtonFlags">1211912703</int> + <int key="NSButtonFlags">1211912448</int> <int key="NSButtonFlags2">2</int> <object class="NSCustomResource" key="NSNormalImage" id="491838135"> <string key="NSClassName">NSImage</string> @@ -222,6 +221,7 @@ <int key="NSPeriodicDelay">200</int> <int key="NSPeriodicInterval">25</int> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSButton" id="806259169"> <reference key="NSNextResponder" ref="1048779201"/> @@ -231,7 +231,7 @@ <reference key="NSNextKeyView" ref="713240777"/> <bool key="NSEnabled">YES</bool> <object class="NSButtonCell" key="NSCell" id="725806271"> - <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags">67108864</int> <int key="NSCellFlags2">134479872</int> <string key="NSContents">Browse ...</string> <object class="NSFont" key="NSSupport" id="22"> @@ -240,13 +240,14 @@ <int key="NSfFlags">3614</int> </object> <reference key="NSControlView" ref="806259169"/> - <int key="NSButtonFlags">-2038284033</int> + <int key="NSButtonFlags">-2038284288</int> <int key="NSButtonFlags2">129</int> <string key="NSAlternateContents"/> <string key="NSKeyEquivalent"/> <int key="NSPeriodicDelay">200</int> <int key="NSPeriodicInterval">25</int> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSTextField" id="842132572"> <reference key="NSNextResponder" ref="1048779201"/> @@ -256,7 +257,7 @@ <reference key="NSNextKeyView" ref="806259169"/> <bool key="NSEnabled">YES</bool> <object class="NSTextFieldCell" key="NSCell" id="456853603"> - <int key="NSCellFlags">68288064</int> + <int key="NSCellFlags">68157504</int> <int key="NSCellFlags2">272761856</int> <string key="NSContents">None</string> <reference key="NSSupport" ref="26"/> @@ -280,6 +281,7 @@ </object> </object> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSButton" id="636306431"> <reference key="NSNextResponder" ref="1048779201"/> @@ -289,12 +291,12 @@ <reference key="NSNextKeyView" ref="280291731"/> <bool key="NSEnabled">YES</bool> <object class="NSButtonCell" key="NSCell" id="448858755"> - <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags">67108864</int> <int key="NSCellFlags2">131072</int> <string key="NSContents">Show Presets Drawer</string> <reference key="NSSupport" ref="26"/> <reference key="NSControlView" ref="636306431"/> - <int key="NSButtonFlags">1211912703</int> + <int key="NSButtonFlags">1211912448</int> <int key="NSButtonFlags2">2</int> <reference key="NSAlternateImage" ref="1056213191"/> <string key="NSAlternateContents"/> @@ -302,6 +304,7 @@ <int key="NSPeriodicDelay">200</int> <int key="NSPeriodicInterval">25</int> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSButton" id="965044526"> <reference key="NSNextResponder" ref="1048779201"/> @@ -311,12 +314,12 @@ <reference key="NSNextKeyView" ref="854927877"/> <bool key="NSEnabled">YES</bool> <object class="NSButtonCell" key="NSCell" id="419322096"> - <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags">67108864</int> <int key="NSCellFlags2">131072</int> <string key="NSContents">Use Auto Naming (uses DVD name and title number)</string> <reference key="NSSupport" ref="26"/> <reference key="NSControlView" ref="965044526"/> - <int key="NSButtonFlags">1211912703</int> + <int key="NSButtonFlags">1211912448</int> <int key="NSButtonFlags2">2</int> <reference key="NSAlternateImage" ref="1056213191"/> <string key="NSAlternateContents"/> @@ -324,6 +327,7 @@ <int key="NSPeriodicDelay">200</int> <int key="NSPeriodicInterval">25</int> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSTextField" id="315188467"> <reference key="NSNextResponder" ref="1048779201"/> @@ -333,7 +337,7 @@ <reference key="NSNextKeyView" ref="23412822"/> <bool key="NSEnabled">YES</bool> <object class="NSTextFieldCell" key="NSCell" id="718672066"> - <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags">67108864</int> <int key="NSCellFlags2">272760832</int> <string key="NSContents">When Done:</string> <reference key="NSSupport" ref="26"/> @@ -341,6 +345,7 @@ <reference key="NSBackgroundColor" ref="525377782"/> <reference key="NSTextColor" ref="887152126"/> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSButton" id="581738572"> <reference key="NSNextResponder" ref="1048779201"/> @@ -350,12 +355,12 @@ <reference key="NSNextKeyView" ref="954667708"/> <bool key="NSEnabled">YES</bool> <object class="NSButtonCell" key="NSCell" id="824062726"> - <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags">67108864</int> <int key="NSCellFlags2">131072</int> <string key="NSContents">Automatically check for updates</string> <reference key="NSSupport" ref="26"/> <reference key="NSControlView" ref="581738572"/> - <int key="NSButtonFlags">1211912703</int> + <int key="NSButtonFlags">1211912448</int> <int key="NSButtonFlags2">2</int> <reference key="NSAlternateImage" ref="1056213191"/> <string key="NSAlternateContents"/> @@ -363,6 +368,7 @@ <int key="NSPeriodicDelay">200</int> <int key="NSPeriodicInterval">25</int> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSButton" id="597305137"> <reference key="NSNextResponder" ref="1048779201"/> @@ -372,12 +378,12 @@ <reference key="NSNextKeyView" ref="842132572"/> <bool key="NSEnabled">YES</bool> <object class="NSButtonCell" key="NSCell" id="437495050"> - <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags">67108864</int> <int key="NSCellFlags2">131072</int> <string key="NSContents">Send file to:</string> <reference key="NSSupport" ref="26"/> <reference key="NSControlView" ref="597305137"/> - <int key="NSButtonFlags">1211912703</int> + <int key="NSButtonFlags">1211912448</int> <int key="NSButtonFlags2">2</int> <reference key="NSNormalImage" ref="491838135"/> <reference key="NSAlternateImage" ref="1056213191"/> @@ -386,6 +392,7 @@ <int key="NSPeriodicDelay">200</int> <int key="NSPeriodicInterval">25</int> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSTextField" id="576686737"> <reference key="NSNextResponder" ref="1048779201"/> @@ -395,7 +402,7 @@ <reference key="NSNextKeyView" ref="636306431"/> <bool key="NSEnabled">YES</bool> <object class="NSTextFieldCell" key="NSCell" id="404194395"> - <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags">67108864</int> <int key="NSCellFlags2">272760832</int> <string key="NSContents">At launch:</string> <reference key="NSSupport" ref="26"/> @@ -403,6 +410,7 @@ <reference key="NSBackgroundColor" ref="525377782"/> <reference key="NSTextColor" ref="887152126"/> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSTextField" id="854927877"> <reference key="NSNextResponder" ref="1048779201"/> @@ -412,7 +420,7 @@ <reference key="NSNextKeyView" ref="317169558"/> <bool key="NSEnabled">YES</bool> <object class="NSTextFieldCell" key="NSCell" id="177949206"> - <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags">67108864</int> <int key="NSCellFlags2">71434240</int> <string key="NSContents">Default MP4 Extension:</string> <reference key="NSSupport" ref="26"/> @@ -420,6 +428,7 @@ <reference key="NSBackgroundColor" ref="525377782"/> <reference key="NSTextColor" ref="887152126"/> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSTextField" id="280291731"> <reference key="NSNextResponder" ref="1048779201"/> @@ -429,7 +438,7 @@ <reference key="NSNextKeyView" ref="54712339"/> <bool key="NSEnabled">YES</bool> <object class="NSTextFieldCell" key="NSCell" id="1049782015"> - <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags">67108864</int> <int key="NSCellFlags2">71434240</int> <string key="NSContents">Source selection:</string> <reference key="NSSupport" ref="26"/> @@ -437,6 +446,7 @@ <reference key="NSBackgroundColor" ref="525377782"/> <reference key="NSTextColor" ref="887152126"/> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSTextField" id="713240777"> <reference key="NSNextResponder" ref="1048779201"/> @@ -446,7 +456,7 @@ <reference key="NSNextKeyView" ref="965044526"/> <bool key="NSEnabled">YES</bool> <object class="NSTextFieldCell" key="NSCell" id="947435557"> - <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags">67108864</int> <int key="NSCellFlags2">272760832</int> <string key="NSContents">Output files:</string> <reference key="NSSupport" ref="26"/> @@ -454,6 +464,7 @@ <reference key="NSBackgroundColor" ref="525377782"/> <reference key="NSTextColor" ref="887152126"/> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSPopUpButton" id="317169558"> <reference key="NSNextResponder" ref="1048779201"/> @@ -462,11 +473,11 @@ <reference key="NSSuperview" ref="1048779201"/> <bool key="NSEnabled">YES</bool> <object class="NSPopUpButtonCell" key="NSCell" id="792374025"> - <int key="NSCellFlags">71433792</int> + <int key="NSCellFlags">71303232</int> <int key="NSCellFlags2">264192</int> <reference key="NSSupport" ref="22"/> <reference key="NSControlView" ref="317169558"/> - <int key="NSButtonFlags">109199615</int> + <int key="NSButtonFlags">109199360</int> <int key="NSButtonFlags2">1</int> <object class="NSFont" key="NSAlternateImage"> <string key="NSName">LucidaGrande</string> @@ -528,6 +539,7 @@ <bool key="NSAltersState">YES</bool> <int key="NSArrowPosition">1</int> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSPopUpButton" id="954667708"> <reference key="NSNextResponder" ref="1048779201"/> @@ -537,11 +549,11 @@ <reference key="NSNextKeyView" ref="315188467"/> <bool key="NSEnabled">YES</bool> <object class="NSPopUpButtonCell" key="NSCell" id="841218599"> - <int key="NSCellFlags">71433792</int> + <int key="NSCellFlags">71303232</int> <int key="NSCellFlags2">133120</int> <reference key="NSSupport" ref="26"/> <reference key="NSControlView" ref="954667708"/> - <int key="NSButtonFlags">109199615</int> + <int key="NSButtonFlags">109199360</int> <int key="NSButtonFlags2">1</int> <object class="NSFont" key="NSAlternateImage" id="44722471"> <string key="NSName">LucidaGrande</string> @@ -607,6 +619,7 @@ <bool key="NSAltersState">YES</bool> <int key="NSArrowPosition">1</int> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSPopUpButton" id="54712339"> <reference key="NSNextResponder" ref="1048779201"/> @@ -616,11 +629,11 @@ <reference key="NSNextKeyView" ref="581738572"/> <bool key="NSEnabled">YES</bool> <object class="NSPopUpButtonCell" key="NSCell" id="310956178"> - <int key="NSCellFlags">71433792</int> + <int key="NSCellFlags">71303232</int> <int key="NSCellFlags2">133120</int> <reference key="NSSupport" ref="26"/> <reference key="NSControlView" ref="54712339"/> - <int key="NSButtonFlags">109199615</int> + <int key="NSButtonFlags">109199360</int> <int key="NSButtonFlags2">1</int> <reference key="NSAlternateImage" ref="44722471"/> <string key="NSAlternateContents"/> @@ -679,9 +692,11 @@ <bool key="NSAltersState">YES</bool> <int key="NSArrowPosition">1</int> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> </object> <string key="NSFrameSize">{460, 256}</string> + <reference key="NSSuperview"/> <reference key="NSNextKeyView" ref="576686737"/> <string key="NSClassName">NSView</string> <string key="NSExtension">NSControl</string> @@ -696,11 +711,9 @@ <int key="NSvFlags">268</int> <string key="NSFrame">{{34, 42}, {432, 17}}</string> <reference key="NSSuperview" ref="520288288"/> - <reference key="NSWindow"/> - <reference key="NSNextKeyView"/> <bool key="NSEnabled">YES</bool> <object class="NSTextFieldCell" key="NSCell" id="374363387"> - <int key="NSCellFlags">67239488</int> + <int key="NSCellFlags">67108928</int> <int key="NSCellFlags2">138413056</int> <string key="NSContents">Nothing here right now, but I am sure we will think of something</string> <reference key="NSSupport" ref="964910696"/> @@ -708,11 +721,11 @@ <reference key="NSBackgroundColor" ref="525377782"/> <reference key="NSTextColor" ref="887152126"/> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> </object> <string key="NSFrameSize">{496, 82}</string> <reference key="NSSuperview"/> - <reference key="NSWindow"/> <reference key="NSNextKeyView" ref="539748933"/> <string key="NSClassName">NSView</string> <string key="NSExtension">NSResponder</string> @@ -731,7 +744,7 @@ <reference key="NSNextKeyView" ref="113289239"/> <bool key="NSEnabled">YES</bool> <object class="NSTextFieldCell" key="NSCell" id="603140150"> - <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags">67108864</int> <int key="NSCellFlags2">272760832</int> <string key="NSContents">Alternate Language:</string> <reference key="NSSupport" ref="26"/> @@ -739,6 +752,7 @@ <reference key="NSBackgroundColor" ref="525377782"/> <reference key="NSTextColor" ref="887152126"/> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSComboBox" id="113289239"> <reference key="NSNextResponder" ref="332598366"/> @@ -746,10 +760,10 @@ <string key="NSFrame">{{169, 87}, {247, 22}}</string> <reference key="NSSuperview" ref="332598366"/> <reference key="NSWindow"/> - <reference key="NSNextKeyView" ref="247298122"/> + <reference key="NSNextKeyView"/> <bool key="NSEnabled">YES</bool> <object class="NSComboBoxCell" key="NSCell" id="37767182"> - <int key="NSCellFlags">343014976</int> + <int key="NSCellFlags">342884416</int> <int key="NSCellFlags2">272761856</int> <string key="NSContents"/> <reference key="NSSupport" ref="26"/> @@ -943,6 +957,8 @@ <reference key="NSSuperview"/> <reference key="NSWindow"/> <bool key="NSEnabled">YES</bool> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> + <bool key="NSControlAllowsExpansionToolTips">YES</bool> <object class="NSMutableArray" key="NSTableColumns"> <bool key="EncodedWithXMLCoder">YES</bool> <object class="NSTableColumn"> @@ -950,7 +966,7 @@ <double key="NSMinWidth">10</double> <double key="NSMaxWidth">1000</double> <object class="NSTableHeaderCell" key="NSHeaderCell"> - <int key="NSCellFlags">75628032</int> + <int key="NSCellFlags">75497472</int> <int key="NSCellFlags2">0</int> <object class="NSMutableString" key="NSContents"> <characters key="NS.bytes"/> @@ -967,7 +983,7 @@ <reference key="NSTextColor" ref="993015046"/> </object> <object class="NSTextFieldCell" key="NSDataCell"> - <int key="NSCellFlags">338820672</int> + <int key="NSCellFlags">338690112</int> <int key="NSCellFlags2">1024</int> <reference key="NSSupport" ref="26"/> <reference key="NSControlView" ref="734498420"/> @@ -1011,6 +1027,7 @@ <int key="NSTableViewGroupRowStyle">1</int> </object> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSTextField" id="389101877"> <reference key="NSNextResponder" ref="332598366"/> @@ -1021,7 +1038,7 @@ <reference key="NSNextKeyView" ref="172081130"/> <bool key="NSEnabled">YES</bool> <object class="NSTextFieldCell" key="NSCell" id="459708758"> - <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags">67108864</int> <int key="NSCellFlags2">272760832</int> <string key="NSContents">Native Language:</string> <reference key="NSSupport" ref="26"/> @@ -1029,24 +1046,7 @@ <reference key="NSBackgroundColor" ref="525377782"/> <reference key="NSTextColor" ref="887152126"/> </object> - </object> - <object class="NSTextField" id="247298122"> - <reference key="NSNextResponder" ref="332598366"/> - <int key="NSvFlags">256</int> - <string key="NSFrame">{{90, 55}, {31, 14}}</string> - <reference key="NSSuperview" ref="332598366"/> - <reference key="NSWindow"/> - <reference key="NSNextKeyView" ref="1054432492"/> - <bool key="NSEnabled">YES</bool> - <object class="NSTextFieldCell" key="NSCell" id="954547948"> - <int key="NSCellFlags">67239424</int> - <int key="NSCellFlags2">272760832</int> - <string key="NSContents">AAC:</string> - <reference key="NSSupport" ref="26"/> - <reference key="NSControlView" ref="247298122"/> - <reference key="NSBackgroundColor" ref="525377782"/> - <reference key="NSTextColor" ref="887152126"/> - </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSComboBox" id="172081130"> <reference key="NSNextResponder" ref="332598366"/> @@ -1057,7 +1057,7 @@ <reference key="NSNextKeyView" ref="725503362"/> <bool key="NSEnabled">YES</bool> <object class="NSComboBoxCell" key="NSCell" id="210320026"> - <int key="NSCellFlags">343014976</int> + <int key="NSCellFlags">342884416</int> <int key="NSCellFlags2">272761856</int> <string key="NSContents">English</string> <reference key="NSSupport" ref="26"/> @@ -1243,6 +1243,8 @@ <reference key="NSSuperview"/> <reference key="NSWindow"/> <bool key="NSEnabled">YES</bool> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> + <bool key="NSControlAllowsExpansionToolTips">YES</bool> <object class="NSMutableArray" key="NSTableColumns"> <bool key="EncodedWithXMLCoder">YES</bool> <object class="NSTableColumn"> @@ -1250,7 +1252,7 @@ <double key="NSMinWidth">10</double> <double key="NSMaxWidth">1000</double> <object class="NSTableHeaderCell" key="NSHeaderCell"> - <int key="NSCellFlags">75628032</int> + <int key="NSCellFlags">75497472</int> <int key="NSCellFlags2">0</int> <object class="NSMutableString" key="NSContents"> <characters key="NS.bytes"/> @@ -1263,7 +1265,7 @@ <reference key="NSTextColor" ref="993015046"/> </object> <object class="NSTextFieldCell" key="NSDataCell"> - <int key="NSCellFlags">338820672</int> + <int key="NSCellFlags">338690112</int> <int key="NSCellFlags2">1024</int> <reference key="NSSupport" ref="26"/> <reference key="NSControlView" ref="686758712"/> @@ -1294,22 +1296,22 @@ <int key="NSTableViewGroupRowStyle">1</int> </object> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSButton" id="168948265"> <reference key="NSNextResponder" ref="332598366"/> <int key="NSvFlags">256</int> - <string key="NSFrame">{{91, 18}, {292, 26}}</string> + <string key="NSFrame">{{122, 45}, {248, 26}}</string> <reference key="NSSuperview" ref="332598366"/> <reference key="NSWindow"/> - <reference key="NSNextKeyView"/> <bool key="NSEnabled">YES</bool> <object class="NSButtonCell" key="NSCell" id="686321393"> - <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags">67108864</int> <int key="NSCellFlags2">0</int> <string key="NSContents">Show advanced options for Auto Passthru</string> <reference key="NSSupport" ref="26"/> <reference key="NSControlView" ref="168948265"/> - <int key="NSButtonFlags">1211912703</int> + <int key="NSButtonFlags">1211912448</int> <int key="NSButtonFlags2">2</int> <reference key="NSAlternateImage" ref="1056213191"/> <string key="NSAlternateContents"/> @@ -1317,30 +1319,7 @@ <int key="NSPeriodicDelay">200</int> <int key="NSPeriodicInterval">25</int> </object> - </object> - <object class="NSButton" id="1054432492"> - <reference key="NSNextResponder" ref="332598366"/> - <int key="NSvFlags">268</int> - <string key="NSFrame">{{123, 53}, {333, 18}}</string> - <reference key="NSSuperview" ref="332598366"/> - <reference key="NSWindow"/> - <reference key="NSNextKeyView" ref="168948265"/> - <bool key="NSEnabled">YES</bool> - <object class="NSButtonCell" key="NSCell" id="787274685"> - <int key="NSCellFlags">-2080244224</int> - <int key="NSCellFlags2">131072</int> - <string key="NSContents">Use CoreAudio instead of FAAC for Built-In Presets</string> - <reference key="NSSupport" ref="26"/> - <reference key="NSControlView" ref="1054432492"/> - <int key="NSButtonFlags">1211912703</int> - <int key="NSButtonFlags2">130</int> - <reference key="NSNormalImage" ref="491838135"/> - <reference key="NSAlternateImage" ref="1056213191"/> - <string key="NSAlternateContents"/> - <string key="NSKeyEquivalent"/> - <int key="NSPeriodicDelay">200</int> - <int key="NSPeriodicInterval">25</int> - </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> </object> <string key="NSFrameSize">{492, 157}</string> @@ -1353,7 +1332,7 @@ <string key="NSExtension">NSResponder</string> </object> <object class="NSCustomView" id="23728330"> - <reference key="NSNextResponder"/> + <nil key="NSNextResponder"/> <int key="NSvFlags">256</int> <object class="NSMutableArray" key="NSSubviews"> <bool key="EncodedWithXMLCoder">YES</bool> @@ -1362,11 +1341,10 @@ <int key="NSvFlags">268</int> <string key="NSFrame">{{302, 172}, {48, 19}}</string> <reference key="NSSuperview" ref="23728330"/> - <reference key="NSWindow"/> <reference key="NSNextKeyView" ref="701867067"/> <bool key="NSEnabled">YES</bool> <object class="NSTextFieldCell" key="NSCell" id="607341761"> - <int key="NSCellFlags">-1804468671</int> + <int key="NSCellFlags">-1804599231</int> <int key="NSCellFlags2">272761856</int> <string key="NSContents"/> <reference key="NSSupport" ref="26"/> @@ -1380,17 +1358,17 @@ <reference key="NSColor" ref="897199777"/> </object> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSTextField" id="226601760"> <reference key="NSNextResponder" ref="23728330"/> <int key="NSvFlags">256</int> <string key="NSFrame">{{17, 207}, {280, 14}}</string> <reference key="NSSuperview" ref="23728330"/> - <reference key="NSWindow"/> <reference key="NSNextKeyView" ref="822080053"/> <bool key="NSEnabled">YES</bool> <object class="NSTextFieldCell" key="NSCell" id="1064438472"> - <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags">67108864</int> <int key="NSCellFlags2">71434240</int> <string key="NSContents">x264 Constant Quality fractional granularity:</string> <reference key="NSSupport" ref="26"/> @@ -1398,17 +1376,17 @@ <reference key="NSBackgroundColor" ref="525377782"/> <reference key="NSTextColor" ref="887152126"/> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSTextField" id="469378299"> <reference key="NSNextResponder" ref="23728330"/> <int key="NSvFlags">256</int> <string key="NSFrame">{{48, 175}, {249, 14}}</string> <reference key="NSSuperview" ref="23728330"/> - <reference key="NSWindow"/> <reference key="NSNextKeyView" ref="62457548"/> <bool key="NSEnabled">YES</bool> <object class="NSTextFieldCell" key="NSCell" id="552368920"> - <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags">67108864</int> <int key="NSCellFlags2">71434240</int> <string key="NSContents">Minimum length of title to scan (seconds):</string> <reference key="NSSupport" ref="26"/> @@ -1416,17 +1394,17 @@ <reference key="NSBackgroundColor" ref="525377782"/> <reference key="NSTextColor" ref="887152126"/> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSTextField" id="701867067"> <reference key="NSNextResponder" ref="23728330"/> <int key="NSvFlags">256</int> <string key="NSFrame">{{99, 145}, {198, 14}}</string> <reference key="NSSuperview" ref="23728330"/> - <reference key="NSWindow"/> <reference key="NSNextKeyView" ref="772611942"/> <bool key="NSEnabled">YES</bool> <object class="NSTextFieldCell" key="NSCell" id="978611587"> - <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags">67108864</int> <int key="NSCellFlags2">71434240</int> <string key="NSContents">Number of picture previews to scan:</string> <reference key="NSSupport" ref="26"/> @@ -1434,17 +1412,17 @@ <reference key="NSBackgroundColor" ref="525377782"/> <reference key="NSTextColor" ref="887152126"/> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSTextField" id="173328305"> <reference key="NSNextResponder" ref="23728330"/> <int key="NSvFlags">256</int> <string key="NSFrame">{{137, 53}, {160, 15}}</string> <reference key="NSSuperview" ref="23728330"/> - <reference key="NSWindow"/> <reference key="NSNextKeyView" ref="895206300"/> <bool key="NSEnabled">YES</bool> <object class="NSTextFieldCell" key="NSCell" id="271531935"> - <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags">67108864</int> <int key="NSCellFlags2">4325376</int> <string key="NSContents">Activity Log Verbosity Level:</string> <reference key="NSSupport" ref="26"/> @@ -1452,17 +1430,17 @@ <reference key="NSBackgroundColor" ref="525377782"/> <reference key="NSTextColor" ref="887152126"/> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSTextField" id="899831697"> <reference key="NSNextResponder" ref="23728330"/> <int key="NSvFlags">256</int> <string key="NSFrame">{{108, 76}, {27, 14}}</string> <reference key="NSSuperview" ref="23728330"/> - <reference key="NSWindow"/> <reference key="NSNextKeyView" ref="907177043"/> <bool key="NSEnabled">YES</bool> <object class="NSTextFieldCell" key="NSCell" id="483848741"> - <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags">67108864</int> <int key="NSCellFlags2">272760832</int> <string key="NSContents">Log:</string> <reference key="NSSupport" ref="26"/> @@ -1470,17 +1448,17 @@ <reference key="NSBackgroundColor" ref="525377782"/> <reference key="NSTextColor" ref="887152126"/> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSTextField" id="898312631"> <reference key="NSNextResponder" ref="23728330"/> <int key="NSvFlags">256</int> <string key="NSFrame">{{70, 110}, {65, 14}}</string> <reference key="NSSuperview" ref="23728330"/> - <reference key="NSWindow"/> <reference key="NSNextKeyView" ref="745324926"/> <bool key="NSEnabled">YES</bool> <object class="NSTextFieldCell" key="NSCell" id="1062716368"> - <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags">67108864</int> <int key="NSCellFlags2">272760832</int> <string key="NSContents">Dvd-Video:</string> <reference key="NSSupport" ref="26"/> @@ -1488,22 +1466,22 @@ <reference key="NSBackgroundColor" ref="525377782"/> <reference key="NSTextColor" ref="887152126"/> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSButton" id="907177043"> <reference key="NSNextResponder" ref="23728330"/> <int key="NSvFlags">256</int> <string key="NSFrame">{{137, 74}, {304, 18}}</string> <reference key="NSSuperview" ref="23728330"/> - <reference key="NSWindow"/> <reference key="NSNextKeyView" ref="173328305"/> <bool key="NSEnabled">YES</bool> <object class="NSButtonCell" key="NSCell" id="869757541"> - <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags">67108864</int> <int key="NSCellFlags2">131072</int> <string key="NSContents">Put individual encode logs in same location as movie</string> <reference key="NSSupport" ref="26"/> <reference key="NSControlView" ref="907177043"/> - <int key="NSButtonFlags">1211912703</int> + <int key="NSButtonFlags">1211912448</int> <int key="NSButtonFlags2">2</int> <reference key="NSAlternateImage" ref="1056213191"/> <string key="NSAlternateContents"/> @@ -1511,22 +1489,22 @@ <int key="NSPeriodicDelay">200</int> <int key="NSPeriodicInterval">25</int> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSButton" id="745324926"> <reference key="NSNextResponder" ref="23728330"/> <int key="NSvFlags">256</int> <string key="NSFrame">{{137, 108}, {220, 18}}</string> <reference key="NSSuperview" ref="23728330"/> - <reference key="NSWindow"/> <reference key="NSNextKeyView" ref="899831697"/> <bool key="NSEnabled">YES</bool> <object class="NSButtonCell" key="NSCell" id="884409108"> - <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags">67108864</int> <int key="NSCellFlags2">131072</int> <string key="NSContents">Use libdvdnav (instead of libdvdread)</string> <reference key="NSSupport" ref="26"/> <reference key="NSControlView" ref="745324926"/> - <int key="NSButtonFlags">1211912703</int> + <int key="NSButtonFlags">1211912448</int> <int key="NSButtonFlags2">2</int> <reference key="NSAlternateImage" ref="1056213191"/> <string key="NSAlternateContents"/> @@ -1534,22 +1512,21 @@ <int key="NSPeriodicDelay">200</int> <int key="NSPeriodicInterval">25</int> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSButton" id="712613872"> <reference key="NSNextResponder" ref="23728330"/> <int key="NSvFlags">256</int> <string key="NSFrame">{{137, 18}, {217, 18}}</string> <reference key="NSSuperview" ref="23728330"/> - <reference key="NSWindow"/> - <reference key="NSNextKeyView"/> <bool key="NSEnabled">YES</bool> <object class="NSButtonCell" key="NSCell" id="562265695"> - <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags">67108864</int> <int key="NSCellFlags2">131072</int> <string key="NSContents">Alert when updating built-in presets</string> <reference key="NSSupport" ref="26"/> <reference key="NSControlView" ref="712613872"/> - <int key="NSButtonFlags">1211912703</int> + <int key="NSButtonFlags">1211912448</int> <int key="NSButtonFlags2">2</int> <reference key="NSAlternateImage" ref="1056213191"/> <string key="NSAlternateContents"/> @@ -1557,43 +1534,44 @@ <int key="NSPeriodicDelay">200</int> <int key="NSPeriodicInterval">25</int> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSPopUpButton" id="772611942"> <reference key="NSNextResponder" ref="23728330"/> <int key="NSvFlags">268</int> <string key="NSFrame">{{299, 140}, {73, 22}}</string> <reference key="NSSuperview" ref="23728330"/> - <reference key="NSWindow"/> <reference key="NSNextKeyView" ref="898312631"/> <bool key="NSEnabled">YES</bool> <object class="NSPopUpButtonCell" key="NSCell" id="413609467"> - <int key="NSCellFlags">-2076049856</int> + <int key="NSCellFlags">-2076180416</int> <int key="NSCellFlags2">133120</int> <reference key="NSSupport" ref="26"/> <reference key="NSControlView" ref="772611942"/> - <int key="NSButtonFlags">109199615</int> + <int key="NSButtonFlags">109199360</int> <int key="NSButtonFlags2">129</int> <string key="NSAlternateContents"/> <string key="NSKeyEquivalent"/> <int key="NSPeriodicDelay">400</int> <int key="NSPeriodicInterval">75</int> - <nil key="NSMenuItem"/> + <object class="NSMenuItem" key="NSMenuItem" id="165310533"> + <reference key="NSMenu" ref="743346318"/> + <string key="NSTitle">10</string> + <string key="NSKeyEquiv"/> + <int key="NSKeyEquivModMask">1048576</int> + <int key="NSMnemonicLoc">2147483647</int> + <int key="NSState">1</int> + <reference key="NSOnImage" ref="13790404"/> + <reference key="NSMixedImage" ref="218367874"/> + <string key="NSAction">_popUpItemAction:</string> + <reference key="NSTarget" ref="413609467"/> + </object> <bool key="NSMenuItemRespectAlignment">YES</bool> <object class="NSMenu" key="NSMenu" id="743346318"> <string key="NSTitle">OtherViews</string> <object class="NSMutableArray" key="NSMenuItems"> <bool key="EncodedWithXMLCoder">YES</bool> - <object class="NSMenuItem" id="165310533"> - <reference key="NSMenu" ref="743346318"/> - <string key="NSTitle">10</string> - <string key="NSKeyEquiv"/> - <int key="NSKeyEquivModMask">1048576</int> - <int key="NSMnemonicLoc">2147483647</int> - <reference key="NSOnImage" ref="13790404"/> - <reference key="NSMixedImage" ref="218367874"/> - <string key="NSAction">_popUpItemAction:</string> - <reference key="NSTarget" ref="413609467"/> - </object> + <reference ref="165310533"/> <object class="NSMenuItem" id="477590220"> <reference key="NSMenu" ref="743346318"/> <string key="NSTitle">15</string> @@ -1704,21 +1682,21 @@ <bool key="NSAltersState">YES</bool> <int key="NSArrowPosition">2</int> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSPopUpButton" id="822080053"> <reference key="NSNextResponder" ref="23728330"/> <int key="NSvFlags">268</int> <string key="NSFrame">{{299, 202}, {76, 22}}</string> <reference key="NSSuperview" ref="23728330"/> - <reference key="NSWindow"/> <reference key="NSNextKeyView" ref="469378299"/> <bool key="NSEnabled">YES</bool> <object class="NSPopUpButtonCell" key="NSCell" id="434430620"> - <int key="NSCellFlags">-2076049856</int> + <int key="NSCellFlags">-2076180416</int> <int key="NSCellFlags2">133120</int> <reference key="NSSupport" ref="26"/> <reference key="NSControlView" ref="822080053"/> - <int key="NSButtonFlags">109199615</int> + <int key="NSButtonFlags">109199360</int> <int key="NSButtonFlags2">129</int> <string key="NSAlternateContents"/> <string key="NSKeyEquivalent"/> @@ -1781,21 +1759,21 @@ <bool key="NSAltersState">YES</bool> <int key="NSArrowPosition">2</int> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSPopUpButton" id="895206300"> <reference key="NSNextResponder" ref="23728330"/> <int key="NSvFlags">268</int> <string key="NSFrame">{{303, 49}, {66, 22}}</string> <reference key="NSSuperview" ref="23728330"/> - <reference key="NSWindow"/> <reference key="NSNextKeyView" ref="200780219"/> <bool key="NSEnabled">YES</bool> <object class="NSPopUpButtonCell" key="NSCell" id="290473288"> - <int key="NSCellFlags">-2076049856</int> + <int key="NSCellFlags">-2076180416</int> <int key="NSCellFlags2">133120</int> <reference key="NSSupport" ref="26"/> <reference key="NSControlView" ref="895206300"/> - <int key="NSButtonFlags">109199615</int> + <int key="NSButtonFlags">109199360</int> <int key="NSButtonFlags2">129</int> <string key="NSAlternateContents"/> <string key="NSKeyEquivalent"/> @@ -1849,17 +1827,17 @@ <bool key="NSAltersState">YES</bool> <int key="NSArrowPosition">2</int> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSTextField" id="200780219"> <reference key="NSNextResponder" ref="23728330"/> <int key="NSvFlags">256</int> <string key="NSFrame">{{89, 20}, {46, 14}}</string> <reference key="NSSuperview" ref="23728330"/> - <reference key="NSWindow"/> <reference key="NSNextKeyView" ref="712613872"/> <bool key="NSEnabled">YES</bool> <object class="NSTextFieldCell" key="NSCell" id="221545613"> - <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags">67108864</int> <int key="NSCellFlags2">272760832</int> <string key="NSContents">Presets:</string> <reference key="NSSupport" ref="26"/> @@ -1867,11 +1845,10 @@ <reference key="NSBackgroundColor" ref="525377782"/> <reference key="NSTextColor" ref="887152126"/> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> </object> <string key="NSFrameSize">{495, 241}</string> - <reference key="NSSuperview"/> - <reference key="NSWindow"/> <reference key="NSNextKeyView" ref="226601760"/> <object class="NSMutableString" key="NSClassName"> <characters key="NS.bytes">NSView</characters> @@ -2175,22 +2152,6 @@ </object> <object class="IBConnectionRecord"> <object class="IBBindingConnection" key="connection"> - <string key="label">value: values.UseCoreAudio</string> - <reference key="source" ref="1054432492"/> - <reference key="destination" ref="580534391"/> - <object class="NSNibBindingConnector" key="connector"> - <reference key="NSSource" ref="1054432492"/> - <reference key="NSDestination" ref="580534391"/> - <string key="NSLabel">value: values.UseCoreAudio</string> - <string key="NSBinding">value</string> - <string key="NSKeyPath">values.UseCoreAudio</string> - <int key="NSNibBindingConnectorVersion">2</int> - </object> - </object> - <int key="connectionID">409</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBBindingConnection" key="connection"> <string key="label">enabled: automaticallyChecksForUpdates</string> <reference key="source" ref="954667708"/> <reference key="destination" ref="413269307"/> @@ -2478,9 +2439,7 @@ <reference ref="725503362"/> <reference ref="113289239"/> <reference ref="172081130"/> - <reference ref="1054432492"/> <reference ref="168948265"/> - <reference ref="247298122"/> </object> <reference key="parent" ref="0"/> <string key="objectName">Audio</string> @@ -2943,20 +2902,6 @@ <reference key="parent" ref="712613872"/> </object> <object class="IBObjectRecord"> - <int key="objectID">406</int> - <reference key="object" ref="1054432492"/> - <object class="NSMutableArray" key="children"> - <bool key="EncodedWithXMLCoder">YES</bool> - <reference ref="787274685"/> - </object> - <reference key="parent" ref="332598366"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">407</int> - <reference key="object" ref="787274685"/> - <reference key="parent" ref="1054432492"/> - </object> - <object class="IBObjectRecord"> <int key="objectID">410</int> <reference key="object" ref="413269307"/> <reference key="parent" ref="0"/> @@ -3035,20 +2980,6 @@ <reference key="parent" ref="200780219"/> </object> <object class="IBObjectRecord"> - <int key="objectID">446</int> - <reference key="object" ref="247298122"/> - <object class="NSMutableArray" key="children"> - <bool key="EncodedWithXMLCoder">YES</bool> - <reference ref="954547948"/> - </object> - <reference key="parent" ref="332598366"/> - </object> - <object class="IBObjectRecord"> - <int key="objectID">447</int> - <reference key="object" ref="954547948"/> - <reference key="parent" ref="247298122"/> - </object> - <object class="IBObjectRecord"> <int key="objectID">448</int> <reference key="object" ref="842132572"/> <object class="NSMutableArray" key="children"> @@ -3344,8 +3275,6 @@ <string>399.IBPluginDependency</string> <string>401.IBPluginDependency</string> <string>402.IBPluginDependency</string> - <string>406.IBPluginDependency</string> - <string>407.IBPluginDependency</string> <string>410.IBPluginDependency</string> <string>414.IBPluginDependency</string> <string>415.IBPluginDependency</string> @@ -3357,8 +3286,6 @@ <string>443.IBPluginDependency</string> <string>444.IBPluginDependency</string> <string>445.IBPluginDependency</string> - <string>446.IBPluginDependency</string> - <string>447.IBPluginDependency</string> <string>448.IBPluginDependency</string> <string>449.IBPluginDependency</string> <string>450.IBPluginDependency</string> @@ -3397,7 +3324,7 @@ <string>6.IBPluginDependency</string> <string>61.IBPluginDependency</string> </object> - <object class="NSMutableArray" key="dict.values"> + <object class="NSArray" key="dict.values"> <bool key="EncodedWithXMLCoder">YES</bool> <string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string> @@ -3510,10 +3437,6 @@ <string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>{{69, 656}, {500, 200}}</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string> @@ -3570,7 +3493,7 @@ <string>fPictureView</string> <string>fSendEncodeToAppField</string> </object> - <object class="NSMutableArray" key="dict.values"> + <object class="NSArray" key="dict.values"> <bool key="EncodedWithXMLCoder">YES</bool> <string>NSView</string> <string>NSView</string> @@ -3589,7 +3512,7 @@ <string>fPictureView</string> <string>fSendEncodeToAppField</string> </object> - <object class="NSMutableArray" key="dict.values"> + <object class="NSArray" key="dict.values"> <bool key="EncodedWithXMLCoder">YES</bool> <object class="IBToOneOutletInfo"> <string key="name">fAdvancedView</string> @@ -3670,7 +3593,7 @@ <string>NSMenuMixedState</string> <string>NSSwitch</string> </object> - <object class="NSMutableArray" key="dict.values"> + <object class="NSArray" key="dict.values"> <bool key="EncodedWithXMLCoder">YES</bool> <string>{11, 11}</string> <string>{10, 3}</string> diff --git a/macosx/English.lproj/Queue.xib b/macosx/English.lproj/Queue.xib index 4c9d705ca..facf5156f 100644 --- a/macosx/English.lproj/Queue.xib +++ b/macosx/English.lproj/Queue.xib @@ -1,35 +1,42 @@ <?xml version="1.0" encoding="UTF-8"?> -<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10"> +<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="8.00"> <data> - <int key="IBDocument.SystemTarget">1050</int> - <string key="IBDocument.SystemVersion">10F569</string> - <string key="IBDocument.InterfaceBuilderVersion">788</string> - <string key="IBDocument.AppKitVersion">1038.29</string> - <string key="IBDocument.HIToolboxVersion">461.00</string> + <int key="IBDocument.SystemTarget">1060</int> + <string key="IBDocument.SystemVersion">12F30</string> + <string key="IBDocument.InterfaceBuilderVersion">3084</string> + <string key="IBDocument.AppKitVersion">1187.39</string> + <string key="IBDocument.HIToolboxVersion">626.00</string> <object class="NSMutableDictionary" key="IBDocument.PluginVersions"> <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string> - <string key="NS.object.0">788</string> + <string key="NS.object.0">3084</string> </object> - <object class="NSMutableArray" key="IBDocument.EditedObjectIDs"> - <bool key="EncodedWithXMLCoder">YES</bool> - <integer value="2577"/> - <integer value="2649"/> - </object> - <object class="NSArray" key="IBDocument.PluginDependencies"> - <bool key="EncodedWithXMLCoder">YES</bool> + <array key="IBDocument.IntegratedClassDependencies"> + <string>NSButton</string> + <string>NSButtonCell</string> + <string>NSCustomObject</string> + <string>NSCustomView</string> + <string>NSImageCell</string> + <string>NSMenu</string> + <string>NSMenuItem</string> + <string>NSOutlineView</string> + <string>NSScrollView</string> + <string>NSScroller</string> + <string>NSSlider</string> + <string>NSSliderCell</string> + <string>NSTableColumn</string> + <string>NSTextField</string> + <string>NSTextFieldCell</string> + <string>NSView</string> + <string>NSWindowTemplate</string> + </array> + <array key="IBDocument.PluginDependencies"> <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - </object> + </array> <object class="NSMutableDictionary" key="IBDocument.Metadata"> - <bool key="EncodedWithXMLCoder">YES</bool> - <object class="NSArray" key="dict.sortedKeys" id="0"> - <bool key="EncodedWithXMLCoder">YES</bool> - </object> - <object class="NSMutableArray" key="dict.values"> - <bool key="EncodedWithXMLCoder">YES</bool> - </object> + <string key="NS.key.0">PluginDependencyRecalculationVersion</string> + <integer value="1" key="NS.object.0"/> </object> - <object class="NSMutableArray" key="IBDocument.RootObjects" id="543585533"> - <bool key="EncodedWithXMLCoder">YES</bool> + <array class="NSMutableArray" key="IBDocument.RootObjects" id="543585533"> <object class="NSCustomObject" id="678333032"> <string key="NSClassName">HBQueueController</string> </object> @@ -42,55 +49,53 @@ <object class="NSWindowTemplate" id="238545558"> <int key="NSWindowStyleMask">4111</int> <int key="NSWindowBacking">2</int> - <string key="NSWindowRect">{{893, 128}, {587, 432}}</string> + <string key="NSWindowRect">{{893, 128}, {574, 423}}</string> <int key="NSWTFlags">1886912512</int> <string key="NSWindowTitle">Queue - HandBrake</string> <string key="NSWindowClass">NSWindow</string> <object class="NSMutableString" key="NSViewClass"> <characters key="NS.bytes">View</characters> </object> - <string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string> + <nil key="NSUserInterfaceItemIdentifier"/> <string key="NSWindowContentMinSize">{525, 340}</string> <object class="NSView" key="NSWindowView" id="431299686"> <reference key="NSNextResponder"/> <int key="NSvFlags">256</int> - <object class="NSMutableArray" key="NSSubviews"> - <bool key="EncodedWithXMLCoder">YES</bool> + <array class="NSMutableArray" key="NSSubviews"> <object class="NSCustomView" id="60629844"> <reference key="NSNextResponder" ref="431299686"/> <int key="NSvFlags">274</int> - <object class="NSMutableArray" key="NSSubviews"> - <bool key="EncodedWithXMLCoder">YES</bool> + <array class="NSMutableArray" key="NSSubviews"> <object class="NSScrollView" id="9160137"> <reference key="NSNextResponder" ref="60629844"/> <int key="NSvFlags">274</int> - <object class="NSMutableArray" key="NSSubviews"> - <bool key="EncodedWithXMLCoder">YES</bool> + <array class="NSMutableArray" key="NSSubviews"> <object class="NSClipView" id="13598910"> <reference key="NSNextResponder" ref="9160137"/> <int key="NSvFlags">2304</int> - <object class="NSMutableArray" key="NSSubviews"> - <bool key="EncodedWithXMLCoder">YES</bool> + <array class="NSMutableArray" key="NSSubviews"> <object class="NSOutlineView" id="790027174"> <reference key="NSNextResponder" ref="13598910"/> <int key="NSvFlags">4352</int> - <string key="NSFrameSize">{517, 329}</string> + <string key="NSFrameSize">{532, 336}</string> <reference key="NSSuperview" ref="13598910"/> + <reference key="NSWindow"/> <bool key="NSEnabled">YES</bool> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> + <bool key="NSControlAllowsExpansionToolTips">YES</bool> <object class="_NSCornerView" key="NSCornerView"> <nil key="NSNextResponder"/> <int key="NSvFlags">256</int> <string key="NSFrame">{{518, 0}, {16, 17}}</string> </object> - <object class="NSMutableArray" key="NSTableColumns"> - <bool key="EncodedWithXMLCoder">YES</bool> + <array class="NSMutableArray" key="NSTableColumns"> <object class="NSTableColumn" id="821940358"> <string key="NSIdentifier">icon</string> <double key="NSWidth">38</double> <double key="NSMinWidth">38</double> <double key="NSMaxWidth">38</double> <object class="NSTableHeaderCell" key="NSHeaderCell"> - <int key="NSCellFlags">75628096</int> + <int key="NSCellFlags">75497536</int> <int key="NSCellFlags2">2048</int> <string key="NSContents"/> <object class="NSFont" key="NSSupport" id="26"> @@ -118,7 +123,7 @@ </object> </object> <object class="NSImageCell" key="NSDataCell" id="592677893"> - <int key="NSCellFlags">130560</int> + <int key="NSCellFlags">134217728</int> <int key="NSCellFlags2">33554432</int> <int key="NSAlign">3</int> <int key="NSScale">0</int> @@ -132,11 +137,11 @@ </object> <object class="NSTableColumn" id="664777621"> <string key="NSIdentifier">desc</string> - <double key="NSWidth">450</double> + <double key="NSWidth">465</double> <double key="NSMinWidth">40</double> <double key="NSMaxWidth">5000</double> <object class="NSTableHeaderCell" key="NSHeaderCell"> - <int key="NSCellFlags">75628096</int> + <int key="NSCellFlags">75497536</int> <int key="NSCellFlags2">2048</int> <string key="NSContents"/> <reference key="NSSupport" ref="26"/> @@ -147,7 +152,7 @@ <reference key="NSTextColor" ref="204129071"/> </object> <object class="NSTextFieldCell" key="NSDataCell" id="574589932"> - <int key="NSCellFlags">337772032</int> + <int key="NSCellFlags">337641472</int> <int key="NSCellFlags2">0</int> <object class="NSFont" key="NSSupport" id="844481358"> <string key="NSName">LucidaGrande</string> @@ -178,7 +183,7 @@ <double key="NSMinWidth">8</double> <double key="NSMaxWidth">20</double> <object class="NSTableHeaderCell" key="NSHeaderCell"> - <int key="NSCellFlags">75628096</int> + <int key="NSCellFlags">75497536</int> <int key="NSCellFlags2">134219776</int> <string key="NSContents"/> <reference key="NSSupport" ref="26"/> @@ -186,12 +191,12 @@ <reference key="NSTextColor" ref="204129071"/> </object> <object class="NSButtonCell" key="NSDataCell" id="620017021"> - <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags">67108864</int> <int key="NSCellFlags2">134217728</int> <string key="NSContents"/> <reference key="NSSupport" ref="844481358"/> <reference key="NSControlView" ref="790027174"/> - <int key="NSButtonFlags">135020799</int> + <int key="NSButtonFlags">135020544</int> <int key="NSButtonFlags2">6</int> <object class="NSCustomResource" key="NSNormalImage"> <string key="NSClassName">NSImage</string> @@ -204,7 +209,7 @@ </object> <reference key="NSTableView" ref="790027174"/> </object> - </object> + </array> <double key="NSIntercellSpacingWidth">3</double> <double key="NSIntercellSpacingHeight">2</double> <reference key="NSBackgroundColor" ref="983556133"/> @@ -226,10 +231,12 @@ <int key="NSDraggingSourceMaskForNonLocal">0</int> <bool key="NSAllowsTypeSelect">YES</bool> <int key="NSTableViewDraggingDestinationStyle">0</int> + <int key="NSTableViewGroupRowStyle">1</int> </object> - </object> - <string key="NSFrame">{{1, 1}, {517, 329}}</string> + </array> + <string key="NSFrame">{{1, 1}, {532, 336}}</string> <reference key="NSSuperview" ref="9160137"/> + <reference key="NSWindow"/> <reference key="NSNextKeyView" ref="790027174"/> <reference key="NSDocView" ref="790027174"/> <object class="NSColor" key="NSBGColor"> @@ -246,8 +253,10 @@ <object class="NSScroller" id="459639248"> <reference key="NSNextResponder" ref="9160137"/> <int key="NSvFlags">256</int> - <string key="NSFrame">{{518, 1}, {15, 329}}</string> + <string key="NSFrame">{{517, 1}, {16, 336}}</string> <reference key="NSSuperview" ref="9160137"/> + <reference key="NSWindow"/> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> <reference key="NSTarget" ref="9160137"/> <string key="NSAction">_doScroller:</string> <double key="NSPercent">0.71428570000000002</double> @@ -257,29 +266,36 @@ <int key="NSvFlags">-2147483392</int> <string key="NSFrame">{{-100, -100}, {282, 15}}</string> <reference key="NSSuperview" ref="9160137"/> + <reference key="NSWindow"/> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> <int key="NSsFlags">1</int> <reference key="NSTarget" ref="9160137"/> <string key="NSAction">_doScroller:</string> <double key="NSPercent">0.9656652</double> </object> - </object> - <string key="NSFrame">{{20, 20}, {534, 331}}</string> + </array> + <string key="NSFrame">{{20, 20}, {534, 338}}</string> <reference key="NSSuperview" ref="60629844"/> + <reference key="NSWindow"/> <reference key="NSNextKeyView" ref="13598910"/> - <int key="NSsFlags">18</int> + <int key="NSsFlags">133138</int> <reference key="NSVScroller" ref="459639248"/> <reference key="NSHScroller" ref="636348341"/> <reference key="NSContentView" ref="13598910"/> <bytes key="NSScrollAmts">AAAAAAAAAABBmAAAQZgAAA</bytes> + <double key="NSMinMagnification">0.25</double> + <double key="NSMaxMagnification">4</double> + <double key="NSMagnification">1</double> </object> <object class="NSSlider" id="948250828"> <reference key="NSNextResponder" ref="60629844"/> <int key="NSvFlags">-2147483356</int> <string key="NSFrame">{{60, 1}, {180, 16}}</string> <reference key="NSSuperview" ref="60629844"/> + <reference key="NSWindow"/> <bool key="NSEnabled">YES</bool> <object class="NSSliderCell" key="NSCell" id="1016294819"> - <int key="NSCellFlags">67501824</int> + <int key="NSCellFlags">67371264</int> <int key="NSCellFlags2">262144</int> <object class="NSMutableString" key="NSContents"> <characters key="NS.bytes"/> @@ -299,15 +315,17 @@ <bool key="NSAllowsTickMarkValuesOnly">YES</bool> <bool key="NSVertical">NO</bool> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSSlider" id="252090132"> <reference key="NSNextResponder" ref="60629844"/> <int key="NSvFlags">-2147483356</int> <string key="NSFrame">{{296, 2}, {80, 16}}</string> <reference key="NSSuperview" ref="60629844"/> + <reference key="NSWindow"/> <bool key="NSEnabled">YES</bool> <object class="NSSliderCell" key="NSCell" id="271127179"> - <int key="NSCellFlags">67501824</int> + <int key="NSCellFlags">67371264</int> <int key="NSCellFlags2">262144</int> <object class="NSMutableString" key="NSContents"> <characters key="NS.bytes"/> @@ -323,15 +341,17 @@ <bool key="NSAllowsTickMarkValuesOnly">YES</bool> <bool key="NSVertical">NO</bool> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSTextField" id="316422061"> <reference key="NSNextResponder" ref="60629844"/> <int key="NSvFlags">-2147483356</int> <string key="NSFrame">{{17, 0}, {38, 14}}</string> <reference key="NSSuperview" ref="60629844"/> + <reference key="NSWindow"/> <bool key="NSEnabled">YES</bool> <object class="NSTextFieldCell" key="NSCell" id="655488883"> - <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags">67108864</int> <int key="NSCellFlags2">272629760</int> <string key="NSContents">Indent</string> <reference key="NSSupport" ref="26"/> @@ -344,15 +364,17 @@ </object> <reference key="NSTextColor" ref="434514744"/> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSTextField" id="891125080"> <reference key="NSNextResponder" ref="60629844"/> <int key="NSvFlags">-2147483356</int> <string key="NSFrame">{{245, 1}, {46, 14}}</string> <reference key="NSSuperview" ref="60629844"/> + <reference key="NSWindow"/> <bool key="NSEnabled">YES</bool> <object class="NSTextFieldCell" key="NSCell" id="402192242"> - <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags">67108864</int> <int key="NSCellFlags2">272629760</int> <string key="NSContents">Spacing</string> <reference key="NSSupport" ref="26"/> @@ -360,15 +382,17 @@ <reference key="NSBackgroundColor" ref="987568653"/> <reference key="NSTextColor" ref="434514744"/> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSButton" id="1065139278"> <reference key="NSNextResponder" ref="60629844"/> <int key="NSvFlags">292</int> <string key="NSFrame">{{6, -25}, {159, 16}}</string> <reference key="NSSuperview" ref="60629844"/> + <reference key="NSWindow"/> <bool key="NSEnabled">YES</bool> <object class="NSButtonCell" key="NSCell" id="907474520"> - <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags">67108864</int> <int key="NSCellFlags2">134479872</int> <string key="NSContents">quick way to intercept delete key</string> <object class="NSFont" key="NSSupport"> @@ -377,7 +401,7 @@ <int key="NSfFlags">3614</int> </object> <reference key="NSControlView" ref="1065139278"/> - <int key="NSButtonFlags">-2038021889</int> + <int key="NSButtonFlags">-2038022144</int> <int key="NSButtonFlags2">34</int> <object class="NSFont" key="NSAlternateImage"> <string key="NSName">LucidaGrande</string> @@ -389,21 +413,24 @@ <int key="NSPeriodicDelay">200</int> <int key="NSPeriodicInterval">25</int> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> - </object> - <string key="NSFrame">{{0, 9}, {574, 358}}</string> + </array> + <string key="NSFrameSize">{574, 358}</string> <reference key="NSSuperview" ref="431299686"/> + <reference key="NSWindow"/> <string key="NSClassName">NSView</string> <string key="NSExtension">NSResponder</string> </object> <object class="NSTextField" id="463845363"> <reference key="NSNextResponder" ref="431299686"/> <int key="NSvFlags">264</int> - <string key="NSFrame">{{17, 407}, {148, 14}}</string> + <string key="NSFrame">{{17, 399}, {540, 14}}</string> <reference key="NSSuperview" ref="431299686"/> + <reference key="NSWindow"/> <bool key="NSEnabled">YES</bool> <object class="NSTextFieldCell" key="NSCell" id="617812287"> - <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags">67108864</int> <int key="NSCellFlags2">272760832</int> <string key="NSContents">Pending Jobs</string> <reference key="NSSupport" ref="26"/> @@ -411,15 +438,17 @@ <reference key="NSBackgroundColor" ref="987568653"/> <reference key="NSTextColor" ref="434514744"/> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> <object class="NSTextField" id="138063786"> <reference key="NSNextResponder" ref="431299686"/> <int key="NSvFlags">266</int> - <string key="NSFrame">{{17, 373}, {560, 30}}</string> + <string key="NSFrame">{{17, 366}, {540, 29}}</string> <reference key="NSSuperview" ref="431299686"/> + <reference key="NSWindow"/> <bool key="NSEnabled">YES</bool> <object class="NSTextFieldCell" key="NSCell" id="108133680"> - <int key="NSCellFlags">67239424</int> + <int key="NSCellFlags">67108864</int> <int key="NSCellFlags2">4325376</int> <string key="NSContents">There are no jobs currently encoding</string> <reference key="NSSupport" ref="26"/> @@ -427,20 +456,22 @@ <reference key="NSBackgroundColor" ref="987568653"/> <reference key="NSTextColor" ref="434514744"/> </object> + <bool key="NSAllowsLogicalLayoutDirection">NO</bool> </object> - </object> - <string key="NSFrameSize">{587, 432}</string> + </array> + <string key="NSFrameSize">{574, 423}</string> <reference key="NSSuperview"/> + <reference key="NSWindow"/> </object> - <string key="NSScreenRect">{{0, 0}, {1920, 1178}}</string> + <string key="NSScreenRect">{{0, 0}, {2560, 1418}}</string> <string key="NSMinSize">{525, 362}</string> - <string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string> + <string key="NSMaxSize">{10000000000000, 10000000000000}</string> <string key="NSFrameAutosaveName">QueueWindow</string> + <bool key="NSWindowIsRestorable">YES</bool> </object> <object class="NSMenu" id="771940260"> <string key="NSTitle"/> - <object class="NSMutableArray" key="NSMenuItems"> - <bool key="EncodedWithXMLCoder">YES</bool> + <array class="NSMutableArray" key="NSMenuItems"> <object class="NSMenuItem" id="16179858"> <reference key="NSMenu" ref="771940260"/> <string key="NSTitle">Edit</string> @@ -471,12 +502,11 @@ <reference key="NSOnImage" ref="7190541"/> <reference key="NSMixedImage" ref="681624584"/> </object> - </object> + </array> </object> - </object> + </array> <object class="IBObjectContainer" key="IBDocument.Objects"> - <object class="NSMutableArray" key="connectionRecords"> - <bool key="EncodedWithXMLCoder">YES</bool> + <array class="NSMutableArray" key="connectionRecords"> <object class="IBConnectionRecord"> <object class="IBOutletConnection" key="connection"> <string key="label">fQueuePane</string> @@ -495,14 +525,6 @@ </object> <object class="IBConnectionRecord"> <object class="IBOutletConnection" key="connection"> - <string key="label">delegate</string> - <reference key="source" ref="238545558"/> - <reference key="destination" ref="678333032"/> - </object> - <int key="connectionID">2579</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBOutletConnection" key="connection"> <string key="label">fOutlineView</string> <reference key="source" ref="678333032"/> <reference key="destination" ref="790027174"/> @@ -510,22 +532,6 @@ <int key="connectionID">2601</int> </object> <object class="IBConnectionRecord"> - <object class="IBOutletConnection" key="connection"> - <string key="label">dataSource</string> - <reference key="source" ref="790027174"/> - <reference key="destination" ref="678333032"/> - </object> - <int key="connectionID">2602</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBOutletConnection" key="connection"> - <string key="label">delegate</string> - <reference key="source" ref="790027174"/> - <reference key="destination" ref="678333032"/> - </object> - <int key="connectionID">2603</int> - </object> - <object class="IBConnectionRecord"> <object class="IBActionConnection" key="connection"> <string key="label">removeSelectedQueueItem:</string> <reference key="source" ref="678333032"/> @@ -550,14 +556,6 @@ <int key="connectionID">2648</int> </object> <object class="IBConnectionRecord"> - <object class="IBOutletConnection" key="connection"> - <string key="label">menu</string> - <reference key="source" ref="574589932"/> - <reference key="destination" ref="771940260"/> - </object> - <int key="connectionID">2653</int> - </object> - <object class="IBConnectionRecord"> <object class="IBActionConnection" key="connection"> <string key="label">editSelectedQueueItem:</string> <reference key="source" ref="678333032"/> @@ -581,13 +579,44 @@ </object> <int key="connectionID">2657</int> </object> - </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">delegate</string> + <reference key="source" ref="238545558"/> + <reference key="destination" ref="678333032"/> + </object> + <int key="connectionID">2579</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">dataSource</string> + <reference key="source" ref="790027174"/> + <reference key="destination" ref="678333032"/> + </object> + <int key="connectionID">2602</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">delegate</string> + <reference key="source" ref="790027174"/> + <reference key="destination" ref="678333032"/> + </object> + <int key="connectionID">2603</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">menu</string> + <reference key="source" ref="574589932"/> + <reference key="destination" ref="771940260"/> + </object> + <int key="connectionID">2653</int> + </object> + </array> <object class="IBMutableOrderedSet" key="objectRecords"> - <object class="NSArray" key="orderedObjects"> - <bool key="EncodedWithXMLCoder">YES</bool> + <array key="orderedObjects"> <object class="IBObjectRecord"> <int key="objectID">0</int> - <reference key="object" ref="0"/> + <array key="object" id="0"/> <reference key="children" ref="543585533"/> <nil key="parent"/> </object> @@ -606,67 +635,61 @@ <object class="IBObjectRecord"> <int key="objectID">2576</int> <reference key="object" ref="238545558"/> - <object class="NSMutableArray" key="children"> - <bool key="EncodedWithXMLCoder">YES</bool> + <array class="NSMutableArray" key="children"> <reference ref="431299686"/> - </object> + </array> <reference key="parent" ref="0"/> <string key="objectName">Window</string> </object> <object class="IBObjectRecord"> <int key="objectID">2577</int> <reference key="object" ref="431299686"/> - <object class="NSMutableArray" key="children"> - <bool key="EncodedWithXMLCoder">YES</bool> + <array class="NSMutableArray" key="children"> <reference ref="60629844"/> <reference ref="138063786"/> <reference ref="463845363"/> - </object> + </array> <reference key="parent" ref="238545558"/> </object> <object class="IBObjectRecord"> <int key="objectID">2547</int> <reference key="object" ref="60629844"/> - <object class="NSMutableArray" key="children"> - <bool key="EncodedWithXMLCoder">YES</bool> + <array class="NSMutableArray" key="children"> <reference ref="9160137"/> <reference ref="948250828"/> <reference ref="252090132"/> <reference ref="316422061"/> <reference ref="891125080"/> <reference ref="1065139278"/> - </object> + </array> <reference key="parent" ref="431299686"/> </object> <object class="IBObjectRecord"> <int key="objectID">2596</int> <reference key="object" ref="9160137"/> - <object class="NSMutableArray" key="children"> - <bool key="EncodedWithXMLCoder">YES</bool> + <array class="NSMutableArray" key="children"> <reference ref="790027174"/> <reference ref="459639248"/> <reference ref="636348341"/> - </object> + </array> <reference key="parent" ref="60629844"/> </object> <object class="IBObjectRecord"> <int key="objectID">2597</int> <reference key="object" ref="790027174"/> - <object class="NSMutableArray" key="children"> - <bool key="EncodedWithXMLCoder">YES</bool> + <array class="NSMutableArray" key="children"> <reference ref="664777621"/> <reference ref="498008730"/> <reference ref="821940358"/> - </object> + </array> <reference key="parent" ref="9160137"/> </object> <object class="IBObjectRecord"> <int key="objectID">2599</int> <reference key="object" ref="664777621"/> - <object class="NSMutableArray" key="children"> - <bool key="EncodedWithXMLCoder">YES</bool> + <array class="NSMutableArray" key="children"> <reference ref="574589932"/> - </object> + </array> <reference key="parent" ref="790027174"/> </object> <object class="IBObjectRecord"> @@ -677,10 +700,9 @@ <object class="IBObjectRecord"> <int key="objectID">2604</int> <reference key="object" ref="498008730"/> - <object class="NSMutableArray" key="children"> - <bool key="EncodedWithXMLCoder">YES</bool> + <array class="NSMutableArray" key="children"> <reference ref="620017021"/> - </object> + </array> <reference key="parent" ref="790027174"/> </object> <object class="IBObjectRecord"> @@ -691,10 +713,9 @@ <object class="IBObjectRecord"> <int key="objectID">2624</int> <reference key="object" ref="821940358"/> - <object class="NSMutableArray" key="children"> - <bool key="EncodedWithXMLCoder">YES</bool> + <array class="NSMutableArray" key="children"> <reference ref="592677893"/> - </object> + </array> <reference key="parent" ref="790027174"/> </object> <object class="IBObjectRecord"> @@ -705,46 +726,41 @@ <object class="IBObjectRecord"> <int key="objectID">2610</int> <reference key="object" ref="948250828"/> - <object class="NSMutableArray" key="children"> - <bool key="EncodedWithXMLCoder">YES</bool> + <array class="NSMutableArray" key="children"> <reference ref="1016294819"/> - </object> + </array> <reference key="parent" ref="60629844"/> </object> <object class="IBObjectRecord"> <int key="objectID">2611</int> <reference key="object" ref="252090132"/> - <object class="NSMutableArray" key="children"> - <bool key="EncodedWithXMLCoder">YES</bool> + <array class="NSMutableArray" key="children"> <reference ref="271127179"/> - </object> + </array> <reference key="parent" ref="60629844"/> </object> <object class="IBObjectRecord"> <int key="objectID">2614</int> <reference key="object" ref="316422061"/> - <object class="NSMutableArray" key="children"> - <bool key="EncodedWithXMLCoder">YES</bool> + <array class="NSMutableArray" key="children"> <reference ref="655488883"/> - </object> + </array> <reference key="parent" ref="60629844"/> </object> <object class="IBObjectRecord"> <int key="objectID">2615</int> <reference key="object" ref="891125080"/> - <object class="NSMutableArray" key="children"> - <bool key="EncodedWithXMLCoder">YES</bool> + <array class="NSMutableArray" key="children"> <reference ref="402192242"/> - </object> + </array> <reference key="parent" ref="60629844"/> </object> <object class="IBObjectRecord"> <int key="objectID">2622</int> <reference key="object" ref="1065139278"/> - <object class="NSMutableArray" key="children"> - <bool key="EncodedWithXMLCoder">YES</bool> + <array class="NSMutableArray" key="children"> <reference ref="907474520"/> - </object> + </array> <reference key="parent" ref="60629844"/> </object> <object class="IBObjectRecord"> @@ -791,10 +807,9 @@ <object class="IBObjectRecord"> <int key="objectID">2511</int> <reference key="object" ref="463845363"/> - <object class="NSMutableArray" key="children"> - <bool key="EncodedWithXMLCoder">YES</bool> + <array class="NSMutableArray" key="children"> <reference ref="617812287"/> - </object> + </array> <reference key="parent" ref="431299686"/> </object> <object class="IBObjectRecord"> @@ -805,10 +820,9 @@ <object class="IBObjectRecord"> <int key="objectID">2646</int> <reference key="object" ref="138063786"/> - <object class="NSMutableArray" key="children"> - <bool key="EncodedWithXMLCoder">YES</bool> + <array class="NSMutableArray" key="children"> <reference ref="108133680"/> - </object> + </array> <reference key="parent" ref="431299686"/> </object> <object class="IBObjectRecord"> @@ -819,12 +833,11 @@ <object class="IBObjectRecord"> <int key="objectID">2649</int> <reference key="object" ref="771940260"/> - <object class="NSMutableArray" key="children"> - <bool key="EncodedWithXMLCoder">YES</bool> + <array class="NSMutableArray" key="children"> <reference ref="16179858"/> <reference ref="60102320"/> <reference ref="172286461"/> - </object> + </array> <reference key="parent" ref="0"/> <string key="objectName">ContextMenu</string> </object> @@ -843,1084 +856,187 @@ <reference key="object" ref="172286461"/> <reference key="parent" ref="771940260"/> </object> - </object> - </object> - <object class="NSMutableDictionary" key="flattenedProperties"> - <bool key="EncodedWithXMLCoder">YES</bool> - <object class="NSArray" key="dict.sortedKeys"> - <bool key="EncodedWithXMLCoder">YES</bool> - <string>-3.IBPluginDependency</string> - <string>2511.IBPluginDependency</string> - <string>2511.ImportedFromIB2</string> - <string>2547.IBPluginDependency</string> - <string>2547.ImportedFromIB2</string> - <string>2576.IBEditorWindowLastContentRect</string> - <string>2576.IBPluginDependency</string> - <string>2576.IBWindowTemplateEditedContentRect</string> - <string>2576.ImportedFromIB2</string> - <string>2576.windowTemplate.hasMaxSize</string> - <string>2576.windowTemplate.hasMinSize</string> - <string>2576.windowTemplate.maxSize</string> - <string>2576.windowTemplate.minSize</string> - <string>2577.IBPluginDependency</string> - <string>2577.ImportedFromIB2</string> - <string>2596.IBPluginDependency</string> - <string>2596.ImportedFromIB2</string> - <string>2597.CustomClassName</string> - <string>2597.IBPluginDependency</string> - <string>2597.ImportedFromIB2</string> - <string>2599.IBPluginDependency</string> - <string>2599.ImportedFromIB2</string> - <string>2604.IBPluginDependency</string> - <string>2604.ImportedFromIB2</string> - <string>2605.IBPluginDependency</string> - <string>2605.ImportedFromIB2</string> - <string>2609.CustomClassName</string> - <string>2609.IBPluginDependency</string> - <string>2609.ImportedFromIB2</string> - <string>2610.IBPluginDependency</string> - <string>2610.ImportedFromIB2</string> - <string>2611.IBPluginDependency</string> - <string>2611.ImportedFromIB2</string> - <string>2614.IBPluginDependency</string> - <string>2614.ImportedFromIB2</string> - <string>2615.IBPluginDependency</string> - <string>2615.ImportedFromIB2</string> - <string>2622.IBPluginDependency</string> - <string>2622.ImportedFromIB2</string> - <string>2624.IBPluginDependency</string> - <string>2624.ImportedFromIB2</string> - <string>2625.IBPluginDependency</string> - <string>2625.ImportedFromIB2</string> - <string>2637.IBPluginDependency</string> - <string>2638.IBPluginDependency</string> - <string>2639.IBPluginDependency</string> - <string>2640.IBPluginDependency</string> - <string>2641.IBPluginDependency</string> - <string>2642.IBPluginDependency</string> - <string>2643.IBPluginDependency</string> - <string>2643.IBShouldRemoveOnLegacySave</string> - <string>2644.IBPluginDependency</string> - <string>2644.IBShouldRemoveOnLegacySave</string> - <string>2646.IBPluginDependency</string> - <string>2646.ImportedFromIB2</string> - <string>2647.IBPluginDependency</string> - <string>2649.IBEditorWindowLastContentRect</string> - <string>2649.IBPluginDependency</string> - <string>2650.IBPluginDependency</string> - <string>2652.IBPluginDependency</string> - <string>2655.IBPluginDependency</string> - </object> - <object class="NSMutableArray" key="dict.values"> - <bool key="EncodedWithXMLCoder">YES</bool> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <integer value="1"/> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <integer value="1"/> - <string>{{77, 333}, {587, 432}}</string> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <string>{{77, 333}, {587, 432}}</string> - <integer value="1"/> - <boolean value="NO"/> - <integer value="1"/> - <string>{3.40282e+38, 3.40282e+38}</string> - <string>{525, 340}</string> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <integer value="1"/> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <integer value="1"/> - <string>HBQueueOutlineView</string> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <integer value="1"/> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <integer value="1"/> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <integer value="1"/> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <integer value="1"/> - <string>HBImageAndTextCell</string> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <integer value="1"/> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <integer value="1"/> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <integer value="1"/> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <integer value="1"/> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <integer value="1"/> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <integer value="1"/> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <integer value="1"/> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <integer value="1"/> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <integer value="1"/> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <integer value="1"/> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <integer value="1"/> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <string>{{555, 544}, {96, 63}}</string> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - <string>com.apple.InterfaceBuilder.CocoaPlugin</string> - </object> - </object> - <object class="NSMutableDictionary" key="unlocalizedProperties"> - <bool key="EncodedWithXMLCoder">YES</bool> - <reference key="dict.sortedKeys" ref="0"/> - <object class="NSMutableArray" key="dict.values"> - <bool key="EncodedWithXMLCoder">YES</bool> - </object> + </array> </object> + <dictionary class="NSMutableDictionary" key="flattenedProperties"> + <string key="-1.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="-2.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="-3.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="2511.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="2547.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="2576.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="2576.IBWindowTemplateEditedContentRect">{{77, 333}, {587, 432}}</string> + <string key="2577.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="2596.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="2597.CustomClassName">HBQueueOutlineView</string> + <string key="2597.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="2599.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="2604.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="2605.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="2609.CustomClassName">HBImageAndTextCell</string> + <string key="2609.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="2610.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="2611.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="2614.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="2615.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="2622.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="2624.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="2625.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="2637.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="2638.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="2639.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="2640.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="2641.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="2642.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="2643.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <integer value="1" key="2643.IBShouldRemoveOnLegacySave"/> + <string key="2644.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <integer value="1" key="2644.IBShouldRemoveOnLegacySave"/> + <string key="2646.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="2647.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="2649.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="2650.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="2652.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="2655.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> + </dictionary> + <dictionary class="NSMutableDictionary" key="unlocalizedProperties"/> <nil key="activeLocalization"/> - <object class="NSMutableDictionary" key="localizations"> - <bool key="EncodedWithXMLCoder">YES</bool> - <reference key="dict.sortedKeys" ref="0"/> - <object class="NSMutableArray" key="dict.values"> - <bool key="EncodedWithXMLCoder">YES</bool> - </object> - </object> + <dictionary class="NSMutableDictionary" key="localizations"/> <nil key="sourceID"/> <int key="maxID">2657</int> </object> <object class="IBClassDescriber" key="IBDocument.Classes"> - <object class="NSMutableArray" key="referencedPartialClassDescriptions"> - <bool key="EncodedWithXMLCoder">YES</bool> + <array class="NSMutableArray" key="referencedPartialClassDescriptions"> <object class="IBPartialClassDescription"> <string key="className">HBImageAndTextCell</string> <string key="superclassName">NSTextFieldCell</string> <object class="IBClassDescriptionSource" key="sourceIdentifier"> <string key="majorKey">IBProjectSource</string> - <string key="minorKey">HBImageAndTextCell.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">HBImageAndTextCell</string> - <string key="superclassName">NSTextFieldCell</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBUserSource</string> - <string key="minorKey"/> + <string key="minorKey">./Classes/HBImageAndTextCell.h</string> </object> </object> <object class="IBPartialClassDescription"> <string key="className">HBQueueController</string> <string key="superclassName">NSWindowController</string> - <object class="NSMutableDictionary" key="actions"> - <bool key="EncodedWithXMLCoder">YES</bool> - <object class="NSArray" key="dict.sortedKeys"> - <bool key="EncodedWithXMLCoder">YES</bool> - <string>editSelectedQueueItem:</string> - <string>imageSpacingChanged:</string> - <string>indentChanged:</string> - <string>removeSelectedQueueItem:</string> - <string>revealSelectedQueueItem:</string> - <string>showQueueWindow:</string> + <dictionary class="NSMutableDictionary" key="actions"> + <string key="editSelectedQueueItem:">id</string> + <string key="imageSpacingChanged:">id</string> + <string key="indentChanged:">id</string> + <string key="removeSelectedQueueItem:">id</string> + <string key="revealSelectedQueueItem:">id</string> + <string key="showQueueWindow:">id</string> + </dictionary> + <dictionary class="NSMutableDictionary" key="actionInfosByName"> + <object class="IBActionInfo" key="editSelectedQueueItem:"> + <string key="name">editSelectedQueueItem:</string> + <string key="candidateClassName">id</string> </object> - <object class="NSMutableArray" key="dict.values"> - <bool key="EncodedWithXMLCoder">YES</bool> - <string>id</string> - <string>id</string> - <string>id</string> - <string>id</string> - <string>id</string> - <string>id</string> + <object class="IBActionInfo" key="imageSpacingChanged:"> + <string key="name">imageSpacingChanged:</string> + <string key="candidateClassName">id</string> </object> - </object> - <object class="NSMutableDictionary" key="actionInfosByName"> - <bool key="EncodedWithXMLCoder">YES</bool> - <object class="NSArray" key="dict.sortedKeys"> - <bool key="EncodedWithXMLCoder">YES</bool> - <string>editSelectedQueueItem:</string> - <string>imageSpacingChanged:</string> - <string>indentChanged:</string> - <string>removeSelectedQueueItem:</string> - <string>revealSelectedQueueItem:</string> - <string>showQueueWindow:</string> + <object class="IBActionInfo" key="indentChanged:"> + <string key="name">indentChanged:</string> + <string key="candidateClassName">id</string> </object> - <object class="NSMutableArray" key="dict.values"> - <bool key="EncodedWithXMLCoder">YES</bool> - <object class="IBActionInfo"> - <string key="name">editSelectedQueueItem:</string> - <string key="candidateClassName">id</string> - </object> - <object class="IBActionInfo"> - <string key="name">imageSpacingChanged:</string> - <string key="candidateClassName">id</string> - </object> - <object class="IBActionInfo"> - <string key="name">indentChanged:</string> - <string key="candidateClassName">id</string> - </object> - <object class="IBActionInfo"> - <string key="name">removeSelectedQueueItem:</string> - <string key="candidateClassName">id</string> - </object> - <object class="IBActionInfo"> - <string key="name">revealSelectedQueueItem:</string> - <string key="candidateClassName">id</string> - </object> - <object class="IBActionInfo"> - <string key="name">showQueueWindow:</string> - <string key="candidateClassName">id</string> - </object> + <object class="IBActionInfo" key="removeSelectedQueueItem:"> + <string key="name">removeSelectedQueueItem:</string> + <string key="candidateClassName">id</string> </object> - </object> - <object class="NSMutableDictionary" key="outlets"> - <bool key="EncodedWithXMLCoder">YES</bool> - <object class="NSArray" key="dict.sortedKeys"> - <bool key="EncodedWithXMLCoder">YES</bool> - <string>fCurrentJobPane</string> - <string>fIndentation</string> - <string>fJobDescTextField</string> - <string>fJobIconView</string> - <string>fOutlineView</string> - <string>fProgressBar</string> - <string>fProgressTextField</string> - <string>fQueueCountField</string> - <string>fQueuePane</string> - <string>fSpacing</string> + <object class="IBActionInfo" key="revealSelectedQueueItem:"> + <string key="name">revealSelectedQueueItem:</string> + <string key="candidateClassName">id</string> </object> - <object class="NSMutableArray" key="dict.values"> - <bool key="EncodedWithXMLCoder">YES</bool> - <string>NSView</string> - <string>NSSlider</string> - <string>NSTextField</string> - <string>NSImageView</string> - <string>HBQueueOutlineView</string> - <string>NSProgressIndicator</string> - <string>NSTextField</string> - <string>NSTextField</string> - <string>NSView</string> - <string>NSSlider</string> + <object class="IBActionInfo" key="showQueueWindow:"> + <string key="name">showQueueWindow:</string> + <string key="candidateClassName">id</string> </object> - </object> - <object class="NSMutableDictionary" key="toOneOutletInfosByName"> - <bool key="EncodedWithXMLCoder">YES</bool> - <object class="NSArray" key="dict.sortedKeys"> - <bool key="EncodedWithXMLCoder">YES</bool> - <string>fCurrentJobPane</string> - <string>fIndentation</string> - <string>fJobDescTextField</string> - <string>fJobIconView</string> - <string>fOutlineView</string> - <string>fProgressBar</string> - <string>fProgressTextField</string> - <string>fQueueCountField</string> - <string>fQueuePane</string> - <string>fSpacing</string> + </dictionary> + <dictionary class="NSMutableDictionary" key="outlets"> + <string key="fCurrentJobPane">NSView</string> + <string key="fIndentation">NSSlider</string> + <string key="fJobDescTextField">NSTextField</string> + <string key="fJobIconView">NSImageView</string> + <string key="fOutlineView">HBQueueOutlineView</string> + <string key="fProgressBar">NSProgressIndicator</string> + <string key="fProgressTextField">NSTextField</string> + <string key="fQueueCountField">NSTextField</string> + <string key="fQueuePane">NSView</string> + <string key="fSpacing">NSSlider</string> + </dictionary> + <dictionary class="NSMutableDictionary" key="toOneOutletInfosByName"> + <object class="IBToOneOutletInfo" key="fCurrentJobPane"> + <string key="name">fCurrentJobPane</string> + <string key="candidateClassName">NSView</string> </object> - <object class="NSMutableArray" key="dict.values"> - <bool key="EncodedWithXMLCoder">YES</bool> - <object class="IBToOneOutletInfo"> - <string key="name">fCurrentJobPane</string> - <string key="candidateClassName">NSView</string> - </object> - <object class="IBToOneOutletInfo"> - <string key="name">fIndentation</string> - <string key="candidateClassName">NSSlider</string> - </object> - <object class="IBToOneOutletInfo"> - <string key="name">fJobDescTextField</string> - <string key="candidateClassName">NSTextField</string> - </object> - <object class="IBToOneOutletInfo"> - <string key="name">fJobIconView</string> - <string key="candidateClassName">NSImageView</string> - </object> - <object class="IBToOneOutletInfo"> - <string key="name">fOutlineView</string> - <string key="candidateClassName">HBQueueOutlineView</string> - </object> - <object class="IBToOneOutletInfo"> - <string key="name">fProgressBar</string> - <string key="candidateClassName">NSProgressIndicator</string> - </object> - <object class="IBToOneOutletInfo"> - <string key="name">fProgressTextField</string> - <string key="candidateClassName">NSTextField</string> - </object> - <object class="IBToOneOutletInfo"> - <string key="name">fQueueCountField</string> - <string key="candidateClassName">NSTextField</string> - </object> - <object class="IBToOneOutletInfo"> - <string key="name">fQueuePane</string> - <string key="candidateClassName">NSView</string> - </object> - <object class="IBToOneOutletInfo"> - <string key="name">fSpacing</string> - <string key="candidateClassName">NSSlider</string> - </object> + <object class="IBToOneOutletInfo" key="fIndentation"> + <string key="name">fIndentation</string> + <string key="candidateClassName">NSSlider</string> </object> - </object> - <object class="IBClassDescriptionSource" key="sourceIdentifier" id="333889241"> - <string key="majorKey">IBProjectSource</string> - <string key="minorKey">HBQueueController.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">HBQueueController</string> - <string key="superclassName">NSWindowController</string> - <object class="NSMutableDictionary" key="actions"> - <bool key="EncodedWithXMLCoder">YES</bool> - <object class="NSArray" key="dict.sortedKeys"> - <bool key="EncodedWithXMLCoder">YES</bool> - <string>cancelCurrentJob:</string> - <string>revealSelectedJobGroups:</string> - <string>togglePauseResume:</string> - <string>toggleStartCancel:</string> + <object class="IBToOneOutletInfo" key="fJobDescTextField"> + <string key="name">fJobDescTextField</string> + <string key="candidateClassName">NSTextField</string> </object> - <object class="NSMutableArray" key="dict.values"> - <bool key="EncodedWithXMLCoder">YES</bool> - <string>id</string> - <string>id</string> - <string>id</string> - <string>id</string> + <object class="IBToOneOutletInfo" key="fJobIconView"> + <string key="name">fJobIconView</string> + <string key="candidateClassName">NSImageView</string> </object> - </object> - <object class="NSMutableDictionary" key="actionInfosByName"> - <bool key="EncodedWithXMLCoder">YES</bool> - <object class="NSArray" key="dict.sortedKeys"> - <bool key="EncodedWithXMLCoder">YES</bool> - <string>cancelCurrentJob:</string> - <string>revealSelectedJobGroups:</string> - <string>togglePauseResume:</string> - <string>toggleStartCancel:</string> + <object class="IBToOneOutletInfo" key="fOutlineView"> + <string key="name">fOutlineView</string> + <string key="candidateClassName">HBQueueOutlineView</string> </object> - <object class="NSMutableArray" key="dict.values"> - <bool key="EncodedWithXMLCoder">YES</bool> - <object class="IBActionInfo"> - <string key="name">cancelCurrentJob:</string> - <string key="candidateClassName">id</string> - </object> - <object class="IBActionInfo"> - <string key="name">revealSelectedJobGroups:</string> - <string key="candidateClassName">id</string> - </object> - <object class="IBActionInfo"> - <string key="name">togglePauseResume:</string> - <string key="candidateClassName">id</string> - </object> - <object class="IBActionInfo"> - <string key="name">toggleStartCancel:</string> - <string key="candidateClassName">id</string> - </object> + <object class="IBToOneOutletInfo" key="fProgressBar"> + <string key="name">fProgressBar</string> + <string key="candidateClassName">NSProgressIndicator</string> </object> - </object> + <object class="IBToOneOutletInfo" key="fProgressTextField"> + <string key="name">fProgressTextField</string> + <string key="candidateClassName">NSTextField</string> + </object> + <object class="IBToOneOutletInfo" key="fQueueCountField"> + <string key="name">fQueueCountField</string> + <string key="candidateClassName">NSTextField</string> + </object> + <object class="IBToOneOutletInfo" key="fQueuePane"> + <string key="name">fQueuePane</string> + <string key="candidateClassName">NSView</string> + </object> + <object class="IBToOneOutletInfo" key="fSpacing"> + <string key="name">fSpacing</string> + <string key="candidateClassName">NSSlider</string> + </object> + </dictionary> <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBUserSource</string> - <string key="minorKey"/> + <string key="majorKey">IBProjectSource</string> + <string key="minorKey">./Classes/HBQueueController.h</string> </object> </object> <object class="IBPartialClassDescription"> <string key="className">HBQueueOutlineView</string> <string key="superclassName">NSOutlineView</string> - <reference key="sourceIdentifier" ref="333889241"/> - </object> - <object class="IBPartialClassDescription"> - <string key="className">HBQueueOutlineView</string> - <string key="superclassName">NSOutlineView</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBUserSource</string> - <string key="minorKey"/> - </object> - </object> - </object> - <object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+"> - <bool key="EncodedWithXMLCoder">YES</bool> - <object class="IBPartialClassDescription"> - <string key="className">NSActionCell</string> - <string key="superclassName">NSCell</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSActionCell.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSApplication</string> - <string key="superclassName">NSResponder</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier" id="1009815657"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSApplication.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSApplication</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier" id="942825343"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSApplicationScripting.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSApplication</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier" id="874636585"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSColorPanel.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSApplication</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSHelpManager.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSApplication</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSPageLayout.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSApplication</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSUserInterfaceItemSearching.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSButton</string> - <string key="superclassName">NSControl</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSButton.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSButtonCell</string> - <string key="superclassName">NSActionCell</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSButtonCell.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSCell</string> - <string key="superclassName">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSCell.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSControl</string> - <string key="superclassName">NSView</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier" id="596505546"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSControl.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSFormatter</string> - <string key="superclassName">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">Foundation.framework/Headers/NSFormatter.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSImageCell</string> - <string key="superclassName">NSCell</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSImageCell.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSImageView</string> - <string key="superclassName">NSControl</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSImageView.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSMenu</string> - <string key="superclassName">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier" id="721965304"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSMenu.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSMenuItem</string> - <string key="superclassName">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier" id="529283491"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSMenuItem.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSAccessibility.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <reference key="sourceIdentifier" ref="1009815657"/> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <reference key="sourceIdentifier" ref="942825343"/> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <reference key="sourceIdentifier" ref="874636585"/> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <reference key="sourceIdentifier" ref="596505546"/> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSDictionaryController.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSDragging.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSFontManager.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSFontPanel.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSKeyValueBinding.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <reference key="sourceIdentifier" ref="721965304"/> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSNibLoading.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier" id="440847546"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSOutlineView.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSPasteboard.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSSavePanel.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier" id="415747133"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSTableView.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSToolbarItem.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier" id="165950663"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSView.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">Foundation.framework/Headers/NSArchiver.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">Foundation.framework/Headers/NSClassDescription.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">Foundation.framework/Headers/NSError.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">Foundation.framework/Headers/NSFileManager.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">Foundation.framework/Headers/NSKeyValueCoding.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">Foundation.framework/Headers/NSKeyValueObserving.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">Foundation.framework/Headers/NSKeyedArchiver.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">Foundation.framework/Headers/NSObject.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">Foundation.framework/Headers/NSObjectScripting.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">Foundation.framework/Headers/NSPortCoder.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">Foundation.framework/Headers/NSRunLoop.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">Foundation.framework/Headers/NSScriptClassDescription.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">Foundation.framework/Headers/NSScriptKeyValueCoding.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">Foundation.framework/Headers/NSScriptObjectSpecifiers.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">Foundation.framework/Headers/NSScriptWhoseTests.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">Foundation.framework/Headers/NSThread.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">Foundation.framework/Headers/NSURL.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">Foundation.framework/Headers/NSURLConnection.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">Foundation.framework/Headers/NSURLDownload.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">Growl.framework/Headers/GrowlApplicationBridge.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">ImageKit.framework/Headers/IKImageBrowserView.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">ImageKit.framework/Headers/IKSaveOptions.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">ImageKit.framework/Headers/ImageKitDeprecated.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">PDFKit.framework/Headers/PDFDocument.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">PDFKit.framework/Headers/PDFView.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">QTKit.framework/Headers/QTCaptureDecompressedAudioOutput.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">QTKit.framework/Headers/QTCaptureDecompressedVideoOutput.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">QTKit.framework/Headers/QTCaptureFileOutput.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">QTKit.framework/Headers/QTCaptureVideoPreviewOutput.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">QTKit.framework/Headers/QTCaptureView.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">QTKit.framework/Headers/QTMovie.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">QTKit.framework/Headers/QTMovieView.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">QuartzComposer.framework/Headers/QCCompositionParameterView.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">QuartzComposer.framework/Headers/QCCompositionPickerView.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">QuartzFilters.framework/Headers/QuartzFilterManager.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">QuickLookUI.framework/Headers/QLPreviewPanel.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">Sparkle.framework/Headers/SUAppcast.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">Sparkle.framework/Headers/SUUpdater.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSOutlineView</string> - <string key="superclassName">NSTableView</string> - <reference key="sourceIdentifier" ref="440847546"/> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSProgressIndicator</string> - <string key="superclassName">NSView</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSProgressIndicator.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSResponder</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSInterfaceStyle.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSResponder</string> - <string key="superclassName">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSResponder.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSScrollView</string> - <string key="superclassName">NSView</string> <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSScrollView.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSScroller</string> - <string key="superclassName">NSControl</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSScroller.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSSlider</string> - <string key="superclassName">NSControl</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSSlider.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSSliderCell</string> - <string key="superclassName">NSActionCell</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSSliderCell.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSTableColumn</string> - <string key="superclassName">NSObject</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSTableColumn.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSTableView</string> - <string key="superclassName">NSControl</string> - <reference key="sourceIdentifier" ref="415747133"/> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSTextField</string> - <string key="superclassName">NSControl</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSTextField.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSTextFieldCell</string> - <string key="superclassName">NSActionCell</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSTextFieldCell.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSView</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSClipView.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSView</string> - <reference key="sourceIdentifier" ref="529283491"/> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSView</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSRulerView.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSView</string> - <string key="superclassName">NSResponder</string> - <reference key="sourceIdentifier" ref="165950663"/> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSWindow</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSDrawer.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSWindow</string> - <string key="superclassName">NSResponder</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSWindow.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSWindow</string> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSWindowScripting.h</string> - </object> - </object> - <object class="IBPartialClassDescription"> - <string key="className">NSWindowController</string> - <string key="superclassName">NSResponder</string> - <object class="NSMutableDictionary" key="actions"> - <string key="NS.key.0">showWindow:</string> - <string key="NS.object.0">id</string> - </object> - <object class="NSMutableDictionary" key="actionInfosByName"> - <string key="NS.key.0">showWindow:</string> - <object class="IBActionInfo" key="NS.object.0"> - <string key="name">showWindow:</string> - <string key="candidateClassName">id</string> - </object> - </object> - <object class="IBClassDescriptionSource" key="sourceIdentifier"> - <string key="majorKey">IBFrameworkSource</string> - <string key="minorKey">AppKit.framework/Headers/NSWindowController.h</string> + <string key="majorKey">IBProjectSource</string> + <string key="minorKey">./Classes/HBQueueOutlineView.h</string> </object> </object> - </object> + </array> </object> <int key="IBDocument.localizationMode">0</int> <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string> <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies"> <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string> - <integer value="1050" key="NS.object.0"/> + <real value="1060" key="NS.object.0"/> </object> <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies"> <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string> - <integer value="3000" key="NS.object.0"/> + <real value="4200" key="NS.object.0"/> </object> <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool> - <string key="IBDocument.LastKnownRelativeProjectPath">../HandBrake.xcodeproj</string> <int key="IBDocument.defaultPropertyAccessControl">3</int> - <object class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes"> - <bool key="EncodedWithXMLCoder">YES</bool> - <object class="NSArray" key="dict.sortedKeys"> - <bool key="EncodedWithXMLCoder">YES</bool> - <string>Delete</string> - <string>NSMenuCheckmark</string> - <string>NSMenuMixedState</string> - </object> - <object class="NSMutableArray" key="dict.values"> - <bool key="EncodedWithXMLCoder">YES</bool> - <string>{16, 16}</string> - <string>{9, 8}</string> - <string>{7, 2}</string> - </object> - </object> + <dictionary class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes"> + <string key="Delete">{16, 16}</string> + <string key="NSMenuCheckmark">{11, 11}</string> + <string key="NSMenuMixedState">{10, 3}</string> + </dictionary> </data> </archive> diff --git a/macosx/HBAudioController.m b/macosx/HBAudioController.m index 52cc8284b..30a2f5e95 100644 --- a/macosx/HBAudioController.m +++ b/macosx/HBAudioController.m @@ -295,19 +295,8 @@ NSString *HBMixdownChangedNotification = @"HBMixdownChangedNotification"; [newAudio setVideoContainerTag: [self videoContainerTag]]; [newAudio setTrackFromIndex: trackIndex]; - // map faac to ca_aac for built-in presets (can be disabled in preferences) - if (0 == aType && - [[NSUserDefaults standardUserDefaults] boolForKey:@"UseCoreAudio"] && - [[dict objectForKey:@"AudioEncoder"] isEqualToString:@"AAC (faac)"]) - { - key = @"AAC (CoreAudio)"; - } - else - { - key = [dict objectForKey:@"AudioEncoder"]; - } - // map legacy encoder names via libhb + key = [dict objectForKey:@"AudioEncoder"]; if (key != nil) { const char *name; diff --git a/macosx/HBPreferencesController.m b/macosx/HBPreferencesController.m index d7d52d2c2..4e335ee69 100644 --- a/macosx/HBPreferencesController.m +++ b/macosx/HBPreferencesController.m @@ -45,7 +45,6 @@ @"YES", @"CheckForUpdates", @"Open Source", @"LaunchSourceBehavior", @"English", @"DefaultLanguage", - @"YES", @"UseCoreAudio", @"Auto", @"DefaultMpegExtension", @"YES", @"UseDvdNav", @"", @"DefAdvancedx264Flags", diff --git a/macosx/HBPreviewController.m b/macosx/HBPreviewController.m index 5d132a12e..8ea8c9bb3 100644 --- a/macosx/HBPreviewController.m +++ b/macosx/HBPreviewController.m @@ -1278,6 +1278,23 @@ [super keyDown:event]; } +- (void)scrollWheel:(NSEvent *)theEvent +{ + if (!fEncodeState) + { + if ([theEvent deltaY] < 0) + { + [fPictureSlider setIntegerValue:fPicture < [fPictureSlider maxValue] ? fPicture + 1 : fPicture]; + [self pictureSliderChanged:self]; + } + else if ([theEvent deltaY] > 0) + { + [fPictureSlider setIntegerValue:fPicture > [fPictureSlider minValue] ? fPicture - 1 : fPicture]; + [self pictureSliderChanged:self]; + } + } +} + #pragma mark *** QTTime Utilities *** // convert a time value (long) to a QTTime structure diff --git a/macosx/HBQueueController.mm b/macosx/HBQueueController.mm index a121c1826..13e944e02 100644 --- a/macosx/HBQueueController.mm +++ b/macosx/HBQueueController.mm @@ -799,94 +799,22 @@ return ![(HBQueueOutlineView*)outlineView isDragging]; { if ([outlineView isItemExpanded: item]) { - /* Below is the original code to accommodate a live resize, - * however as stated in travistex's comments it's very buggy. - * For now I will leave it here ... commented out and use - * the code below to determine the row height based on each - * encodes optional parameters and how they are displayed. */ + // It is important to use a constant value when calculating the height. Querying the tableColumn width will not work, since it dynamically changes as the user resizes -- however, we don't get a notification that the user "did resize" it until after the mouse is let go. We use the latter as a hook for telling the table that the heights changed. We must return the same height from this method every time, until we tell the table the heights have changed. Not doing so will quicly cause drawing problems. + NSTableColumn *tableColumnToWrap = (NSTableColumn *) [[outlineView tableColumns] objectAtIndex:1]; + NSInteger columnToWrap = [outlineView.tableColumns indexOfObject:tableColumnToWrap]; - // Short-circuit here if in a live resize primarily to fix a bug but also to - // increase resposivness during a resize. There's a bug in NSTableView that - // causes row heights to get messed up if you try to change them during a live - // resize. So if in a live resize, simply return the previously calculated - // height. The row heights will get fixed up after the resize because we have - // implemented viewDidEndLiveResize to force all of them to be recalculated. - // if ([outlineView inLiveResize] && [item lastDescriptionHeight] > 0) - // return [item lastDescriptionHeight]; + // Grab the fully prepared cell with our content filled in. Note that in IB the cell's Layout is set to Wraps. + NSCell *cell = [outlineView preparedCellAtColumn:columnToWrap row:[outlineView rowForItem:item]]; - // CGFloat width = [[outlineView tableColumnWithIdentifier: @"desc"] width]; - // Column width is NOT what is ultimately used. I can't quite figure out what - // width to use for calculating text metrics. No matter how I tweak this value, - // there are a few conditions in which the drawn text extends below the bounds - // of the row cell. In previous versions, which ran under Tiger, I was - // reducing width by 47 pixles. - // width -= 2; // (?) for intercell spacing - - // CGFloat height = [item heightOfDescriptionForWidth: width]; - // return height; - - /* So, we know several rows of text that are in all queue items for display. - * These are the title line, Preset, Format, Destination, Picture, and Video Lines - */ - CGFloat rowHeightNonTitle = 15.0; - /* Add the title line height, then the non title line height for Preset, Format, Destination - * Picture and Video - */ - CGFloat itemHeightForDisplay = HB_ROW_HEIGHT_TITLE_ONLY + (rowHeightNonTitle * 5); - - /* get our item row number so we an use it to calc how many lines we have to display based - * on MP4 Options, Filter Options, X264 Options, Audio Tracks and Subtitles from our queue array */ - int itemRowNum = [outlineView rowForItem: item]; - NSMutableDictionary *queueItemToCheck = [outlineView itemAtRow: itemRowNum]; - - /* Check to see if we need to allow for container options */ - if ([[queueItemToCheck objectForKey:@"MuxerOptionsSummary"] length]) - { - itemHeightForDisplay += rowHeightNonTitle; - } - - /* check to see if we need to allow for the Picture Filters row */ - if ([[queueItemToCheck objectForKey:@"PictureFiltersSummary"] length]) - { - itemHeightForDisplay += rowHeightNonTitle; - } - - /* check to see if we need a line to display x264/lavc options */ - if ([[queueItemToCheck objectForKey:@"VideoEncoder"] isEqualToString: @"H.264 (x264)"]) - { - itemHeightForDisplay += rowHeightNonTitle * 2; - } - else if (![[queueItemToCheck objectForKey:@"VideoEncoder"] isEqualToString: @"VP3 (Theora)"]) - { - itemHeightForDisplay += rowHeightNonTitle; - } - - /* check to see how many audio track lines to allow for */ - unsigned int ourMaximumNumberOfAudioTracks = [HBController maximumNumberOfAllowedAudioTracks]; - int actualCountOfAudioTracks = 0; - BOOL autoPassthruPresent = NO; - for (unsigned int i = 1; i <= ourMaximumNumberOfAudioTracks; i++) { - if (0 < [[queueItemToCheck objectForKey: [NSString stringWithFormat: @"Audio%dTrack", i]] intValue]) - { - actualCountOfAudioTracks++; - } - if (HB_ACODEC_AUTO_PASS == [[queueItemToCheck objectForKey: [NSString stringWithFormat: @"JobAudio%dEncoder", i]] intValue]) - { - autoPassthruPresent = YES; - } - } - itemHeightForDisplay += (actualCountOfAudioTracks * rowHeightNonTitle * 2); - - if (autoPassthruPresent == YES) - { - itemHeightForDisplay += rowHeightNonTitle * 2; - } - - /* add in subtitle lines for each subtitle in the SubtitleList array */ - itemHeightForDisplay += rowHeightNonTitle * [[queueItemToCheck objectForKey:@"SubtitleList"] count]; - - return itemHeightForDisplay; + // See how tall it naturally would want to be if given a restricted with, but unbound height + NSRect constrainedBounds = NSMakeRect(0, 0, [tableColumnToWrap width], CGFLOAT_MAX); + NSSize naturalSize = [cell cellSizeForBounds:constrainedBounds]; + // Make sure we have a minimum height -- use the table's set height as the minimum. + if (naturalSize.height > [outlineView rowHeight]) + return naturalSize.height; + else + return [outlineView rowHeight]; } else { @@ -894,40 +822,6 @@ return ![(HBQueueOutlineView*)outlineView isDragging]; } } -- (CGFloat) heightOfDescriptionForWidth:(CGFloat)width -{ - // Try to return the cached value if no changes have happened since the last time - //if ((width == fLastDescriptionWidth) && (fLastDescriptionHeight != 0) && !fNeedsDescription) - // return fLastDescriptionHeight; - - //if (fNeedsDescription) - // [self updateDescription]; - - // Calculate the height - //NSRect bounds = [fDescription boundingRectWithSize:NSMakeSize(width, 10000) options:NSStringDrawingUsesLineFragmentOrigin]; - //fLastDescriptionHeight = bounds.size.height + 6.0; // add some border to bottom - //fLastDescriptionWidth = width; - return HB_ROW_HEIGHT_FULL_DESCRIPTION; - -/* supposedly another way to do this, in case boundingRectWithSize isn't working - NSTextView* tmpView = [[NSTextView alloc] initWithFrame:NSMakeRect(0, 0, width, 1)]; - [[tmpView textStorage] setAttributedString:aString]; - [tmpView setHorizontallyResizable:NO]; - [tmpView setVerticallyResizable:YES]; -// [[tmpView textContainer] setHeightTracksTextView: YES]; -// [[tmpView textContainer] setContainerSize: NSMakeSize(width, 10000)]; - [tmpView sizeToFit]; - float height = [tmpView frame].size.height; - [tmpView release]; - return height; -*/ -} - -- (CGFloat) lastDescriptionHeight -{ - return HB_ROW_HEIGHT_FULL_DESCRIPTION; -} - - (id)outlineView:(NSOutlineView *)fOutlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item { if ([[tableColumn identifier] isEqualToString:@"desc"]) diff --git a/macosx/HBSubtitles.m b/macosx/HBSubtitles.m index 989374e37..56df55aa0 100644 --- a/macosx/HBSubtitles.m +++ b/macosx/HBSubtitles.m @@ -5,6 +5,7 @@ It may be used under the terms of the GNU General Public License. */ #import "HBSubtitles.h" +#include "lang.h" #include "hb.h" @implementation HBSubtitles @@ -17,194 +18,19 @@ } /* setup our array of languages */ + const iso639_lang_t *lang; languagesArray = [[NSMutableArray alloc] init]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Any",@"und",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Afar",@"aar",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Abkhazian",@"abk",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Afrikaans",@"afr",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Akan",@"ak",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Albanian",@"sqi",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Amharic",@"amh",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Arabic",@"ara",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Aragonese",@"arg",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Armenian",@"hye",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Assamese",@"asm",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Avaric",@"ava",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Avestan",@"ave",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Aymara",@"aym",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Azerbaijani",@"aze",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Bashkir",@"bak",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Bambara",@"bam",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Basque",@"eus",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Belarusian",@"bel",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Bengali",@"ben",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Bihari",@"bih",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Bislama",@"bis",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Bosnian",@"bos",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Breton",@"bre",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Bulgarian",@"bul",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Burmese",@"mya",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Catalan",@"cat",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Chamorro",@"cha",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Chechen",@"che",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Chinese",@"zho",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Church Slavic",@"chu",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Chuvash",@"chv",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Cornish",@"cor",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Corsican",@"cos",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Cree",@"cre",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Czech",@"ces",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Danish",@"dan",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Divehi",@"div",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Dutch",@"nld",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Dzongkha",@"dzo",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"English",@"eng",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Esperanto",@"epo",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Estonian",@"est",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Ewe",@"ewe",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Faroese",@"fao",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Fijian",@"fij",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Finnish",@"fin",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"French",@"fra",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Western Frisian",@"fry",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Fulah",@"ful",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Georgian",@"kat",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"German",@"deu",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Gaelic (Scots)",@"gla",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Irish",@"gle",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Galician",@"glg",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Manx",@"glv",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Greek, Modern",@"ell",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Guarani",@"grn",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Gujarati",@"guj",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Haitian",@"hat",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Hausa",@"hau",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Hebrew",@"heb",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Herero",@"her",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Hindi",@"hin",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Hiri Motu",@"hmo",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Hungarian",@"hun",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Igbo",@"ibo",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Icelandic",@"isl",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Ido",@"ido",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Sichuan Yi",@"iii",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Inuktitut",@"iku",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Interlingue",@"ile",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Interlingua",@"ina",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Indonesian",@"ind",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Inupiaq",@"ipk",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Italian",@"ita",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Javanese",@"jav",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Japanese",@"jpn",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Kalaallisut (Greenlandic)",@"kal",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Kannada",@"kan",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Kashmiri",@"kas",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Kanuri",@"kau",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Kazakh",@"kaz",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Central Khmer",@"khm",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Kikuyu",@"kik",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Kinyarwanda",@"kin",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Kirghiz",@"kir",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Komi",@"kom",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Kongo",@"kon",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Korean",@"kor",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Kuanyama",@"kua",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Kurdish",@"kur",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Lao",@"lao",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Latin",@"lat",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Latvian",@"lav",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Limburgan",@"lim",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Lingala",@"lin",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Lithuanian",@"lit",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Luxembourgish",@"ltz",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Luba-Katanga",@"lub",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Ganda",@"lug",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Macedonian",@"mkd",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Marshallese",@"mah",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Malayalam",@"mal",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Maori",@"mri",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Marathi",@"mar",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Malay",@"msa",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Malagasy",@"mlg",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Maltese",@"mlt",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Moldavian",@"mol",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Mongolian",@"mon",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Nauru",@"nau",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Navajo",@"nav",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Ndebele, South",@"nbl",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Ndebele, North",@"nde",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Ndonga",@"ndo",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Nepali",@"nep",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Norwegian Nynorsk",@"nno",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Norwegian Bokmål",@"nob",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Norwegian",@"nor",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Chichewa; Nyanja",@"nya",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Occitan (post 1500); Provençal",@"oci",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Ojibwa",@"oji",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Oriya",@"ori",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Oromo",@"orm",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Ossetian; Ossetic",@"und",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Panjabi",@"pan",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Persian",@"fas",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Pali",@"pli",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Portuguese",@"por",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Pushto",@"pus",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Quechua",@"que",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Romansh",@"roh",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Romanian",@"ron",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Rundi",@"run",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Russian",@"rus",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Sango",@"sag",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Sanskrit",@"san",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Serbian",@"srp",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Croatian",@"hrv",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Sinhala",@"sin",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Slovak",@"slk",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Slovenian",@"slv",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Northern Sami",@"sme",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Samoan",@"smo",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Shona",@"sna",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Sindhi",@"snd",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Somali",@"som",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Sotho, Southern",@"sot",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Spanish",@"spa",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Sardinian",@"srd",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Swati",@"ssw",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Sundanese",@"sun",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Swahili",@"swa",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Swedish",@"swe",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Tahitian",@"tah",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Tamil",@"tam",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Tatar",@"tat",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Telugu",@"tel",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Tajik",@"tgk",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Tagalog",@"tgl",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Thai",@"tha",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Tibetan",@"bod",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Tigrinya",@"tir",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Tonga (Tonga Islands)",@"ton",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Tswana",@"tsn",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Tsonga",@"tso",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Turkmen",@"tuk",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Turkish",@"tur",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Twi",@"twi",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Uighur",@"uig",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Ukrainian",@"ukr",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Urdu",@"urd",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Uzbek",@"uzb",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Venda",@"ven",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Vietnamese",@"vie",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Volapük",@"vol",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Welsh",@"cym",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Walloon",@"wln",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Wolof",@"wol",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Xhosa",@"xho",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Yiddish",@"yid",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Yoruba",@"yor",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"ZhuangZhuang",@"zha",nil]]; - [languagesArray addObject:[NSArray arrayWithObjects:@"Zulu",@"zul",nil]]; - - languagesArrayDefIndex = 40; + for (lang = lang_get_next(NULL); lang != NULL; lang = lang_get_next(lang)) + { + [languagesArray addObject:[NSArray arrayWithObjects: + [NSString stringWithUTF8String:lang->eng_name], + [NSString stringWithUTF8String:lang->iso639_2], + nil]]; + if (!strcasecmp(lang->eng_name, "English")) + { + languagesArrayDefIndex = [languagesArray count] - 1; + } + } /* populate the charCodeArray */ charCodeArray = [[NSMutableArray alloc] init]; diff --git a/macosx/HandBrake.xcodeproj/project.pbxproj b/macosx/HandBrake.xcodeproj/project.pbxproj index 9fd6f4e9a..a2dcbaccd 100644 --- a/macosx/HandBrake.xcodeproj/project.pbxproj +++ b/macosx/HandBrake.xcodeproj/project.pbxproj @@ -94,20 +94,14 @@ 27D6C75014B102DA00B785E4 /* libdvdnav.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C72E14B102DA00B785E4 /* libdvdnav.a */; }; 27D6C75114B102DA00B785E4 /* libdvdread.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C72F14B102DA00B785E4 /* libdvdread.a */; }; 27D6C75214B102DA00B785E4 /* libdvdread.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C72F14B102DA00B785E4 /* libdvdread.a */; }; - 27D6C75314B102DA00B785E4 /* libfaac.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C73014B102DA00B785E4 /* libfaac.a */; }; - 27D6C75414B102DA00B785E4 /* libfaac.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C73014B102DA00B785E4 /* libfaac.a */; }; 27D6C75514B102DA00B785E4 /* libfontconfig.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C73114B102DA00B785E4 /* libfontconfig.a */; }; 27D6C75614B102DA00B785E4 /* libfontconfig.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C73114B102DA00B785E4 /* libfontconfig.a */; }; 27D6C75714B102DA00B785E4 /* libfreetype.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C73214B102DA00B785E4 /* libfreetype.a */; }; 27D6C75814B102DA00B785E4 /* libfreetype.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C73214B102DA00B785E4 /* libfreetype.a */; }; 27D6C75914B102DA00B785E4 /* libfribidi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C73314B102DA00B785E4 /* libfribidi.a */; }; 27D6C75A14B102DA00B785E4 /* libfribidi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C73314B102DA00B785E4 /* libfribidi.a */; }; - 27D6C75B14B102DA00B785E4 /* libmkv.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C73414B102DA00B785E4 /* libmkv.a */; }; - 27D6C75C14B102DA00B785E4 /* libmkv.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C73414B102DA00B785E4 /* libmkv.a */; }; 27D6C75E14B102DA00B785E4 /* libmp3lame.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C73614B102DA00B785E4 /* libmp3lame.a */; }; 27D6C75F14B102DA00B785E4 /* libmp3lame.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C73614B102DA00B785E4 /* libmp3lame.a */; }; - 27D6C76014B102DA00B785E4 /* libmp4v2.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C73714B102DA00B785E4 /* libmp4v2.a */; }; - 27D6C76114B102DA00B785E4 /* libmp4v2.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C73714B102DA00B785E4 /* libmp4v2.a */; }; 27D6C76214B102DA00B785E4 /* libmpeg2.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C73814B102DA00B785E4 /* libmpeg2.a */; }; 27D6C76314B102DA00B785E4 /* libmpeg2.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C73814B102DA00B785E4 /* libmpeg2.a */; }; 27D6C76414B102DA00B785E4 /* libogg.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C73914B102DA00B785E4 /* libogg.a */; }; @@ -297,13 +291,10 @@ 27D6C72C14B102DA00B785E4 /* libbluray.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libbluray.a; path = external/contrib/lib/libbluray.a; sourceTree = BUILT_PRODUCTS_DIR; }; 27D6C72E14B102DA00B785E4 /* libdvdnav.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libdvdnav.a; path = external/contrib/lib/libdvdnav.a; sourceTree = BUILT_PRODUCTS_DIR; }; 27D6C72F14B102DA00B785E4 /* libdvdread.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libdvdread.a; path = external/contrib/lib/libdvdread.a; sourceTree = BUILT_PRODUCTS_DIR; }; - 27D6C73014B102DA00B785E4 /* libfaac.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libfaac.a; path = external/contrib/lib/libfaac.a; sourceTree = BUILT_PRODUCTS_DIR; }; 27D6C73114B102DA00B785E4 /* libfontconfig.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libfontconfig.a; path = external/contrib/lib/libfontconfig.a; sourceTree = BUILT_PRODUCTS_DIR; }; 27D6C73214B102DA00B785E4 /* libfreetype.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libfreetype.a; path = external/contrib/lib/libfreetype.a; sourceTree = BUILT_PRODUCTS_DIR; }; 27D6C73314B102DA00B785E4 /* libfribidi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libfribidi.a; path = external/contrib/lib/libfribidi.a; sourceTree = BUILT_PRODUCTS_DIR; }; - 27D6C73414B102DA00B785E4 /* libmkv.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmkv.a; path = external/contrib/lib/libmkv.a; sourceTree = BUILT_PRODUCTS_DIR; }; 27D6C73614B102DA00B785E4 /* libmp3lame.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmp3lame.a; path = external/contrib/lib/libmp3lame.a; sourceTree = BUILT_PRODUCTS_DIR; }; - 27D6C73714B102DA00B785E4 /* libmp4v2.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmp4v2.a; path = external/contrib/lib/libmp4v2.a; sourceTree = BUILT_PRODUCTS_DIR; }; 27D6C73814B102DA00B785E4 /* libmpeg2.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmpeg2.a; path = external/contrib/lib/libmpeg2.a; sourceTree = BUILT_PRODUCTS_DIR; }; 27D6C73914B102DA00B785E4 /* libogg.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libogg.a; path = external/contrib/lib/libogg.a; sourceTree = BUILT_PRODUCTS_DIR; }; 27D6C73A14B102DA00B785E4 /* libsamplerate.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libsamplerate.a; path = external/contrib/lib/libsamplerate.a; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -372,13 +363,10 @@ 27D6C74C14B102DA00B785E4 /* libbluray.a in Frameworks */, 27D6C75014B102DA00B785E4 /* libdvdnav.a in Frameworks */, 27D6C75214B102DA00B785E4 /* libdvdread.a in Frameworks */, - 27D6C75414B102DA00B785E4 /* libfaac.a in Frameworks */, 27D6C75614B102DA00B785E4 /* libfontconfig.a in Frameworks */, 27D6C75814B102DA00B785E4 /* libfreetype.a in Frameworks */, 27D6C75A14B102DA00B785E4 /* libfribidi.a in Frameworks */, - 27D6C75C14B102DA00B785E4 /* libmkv.a in Frameworks */, 27D6C75F14B102DA00B785E4 /* libmp3lame.a in Frameworks */, - 27D6C76114B102DA00B785E4 /* libmp4v2.a in Frameworks */, 27D6C76314B102DA00B785E4 /* libmpeg2.a in Frameworks */, 27D6C76514B102DA00B785E4 /* libogg.a in Frameworks */, 27D6C76714B102DA00B785E4 /* libsamplerate.a in Frameworks */, @@ -416,13 +404,10 @@ 27D6C74B14B102DA00B785E4 /* libbluray.a in Frameworks */, 27D6C74F14B102DA00B785E4 /* libdvdnav.a in Frameworks */, 27D6C75114B102DA00B785E4 /* libdvdread.a in Frameworks */, - 27D6C75314B102DA00B785E4 /* libfaac.a in Frameworks */, 27D6C75514B102DA00B785E4 /* libfontconfig.a in Frameworks */, 27D6C75714B102DA00B785E4 /* libfreetype.a in Frameworks */, 27D6C75914B102DA00B785E4 /* libfribidi.a in Frameworks */, - 27D6C75B14B102DA00B785E4 /* libmkv.a in Frameworks */, 27D6C75E14B102DA00B785E4 /* libmp3lame.a in Frameworks */, - 27D6C76014B102DA00B785E4 /* libmp4v2.a in Frameworks */, 27D6C76214B102DA00B785E4 /* libmpeg2.a in Frameworks */, 27D6C76414B102DA00B785E4 /* libogg.a in Frameworks */, 27D6C76614B102DA00B785E4 /* libsamplerate.a in Frameworks */, @@ -451,13 +436,10 @@ 27D6C72C14B102DA00B785E4 /* libbluray.a */, 27D6C72E14B102DA00B785E4 /* libdvdnav.a */, 27D6C72F14B102DA00B785E4 /* libdvdread.a */, - 27D6C73014B102DA00B785E4 /* libfaac.a */, 27D6C73114B102DA00B785E4 /* libfontconfig.a */, 27D6C73214B102DA00B785E4 /* libfreetype.a */, 27D6C73314B102DA00B785E4 /* libfribidi.a */, - 27D6C73414B102DA00B785E4 /* libmkv.a */, 27D6C73614B102DA00B785E4 /* libmp3lame.a */, - 27D6C73714B102DA00B785E4 /* libmp4v2.a */, 27D6C73814B102DA00B785E4 /* libmpeg2.a */, 27D6C73914B102DA00B785E4 /* libogg.a */, 27D6C73A14B102DA00B785E4 /* libsamplerate.a */, diff --git a/macosx/module.defs b/macosx/module.defs index 39230cd6f..39edaa405 100644 --- a/macosx/module.defs +++ b/macosx/module.defs @@ -30,9 +30,22 @@ MACOSX.extra_cflags = OTHER_CFLAGS='-DUSE_OPENCL' endif ifeq (1,$(FEATURE.fdk_aac)) -MACOSX.extra_ldflags = OTHER_LDFLAGS='$(abspath $(BUILD))/contrib/lib/libfdk-aac.a' + extra_libs += $(abspath $(BUILD))/contrib/lib/libfdk-aac.a endif +ifeq (1,$(FEATURE.faac)) + extra_libs += $(abspath $(BUILD))/contrib/lib/libfaac.a +endif + +ifeq (1,$(FEATURE.mp4v2)) + extra_libs += $(abspath $(BUILD))/contrib/lib/libmp4v2.a +endif + +ifeq (1,$(FEATURE.libmkv)) + extra_libs += $(abspath $(BUILD))/contrib/lib/libmkv.a +endif +MACOSX.extra_ldflags = OTHER_LDFLAGS='$(extra_libs)' + ## xcconfig: must be one of macosx/xcconfig/*.xcconfig MACOSX.xcconfig = $(foreach x,$(XCODE.xcconfig),-xcconfig $(MACOSX.src/)xcconfig/$(x)) MACOSX.sdk = $(foreach sdk,$(GCC.sysroot),-sdk $(sdk)) diff --git a/make/configure.py b/make/configure.py index 7c1ef868e..4d6dfe59d 100644 --- a/make/configure.py +++ b/make/configure.py @@ -1175,13 +1175,37 @@ def createCLI(): grp.add_option( '--disable-gst', default=False, action='store_true', help=h ) h = IfHost( 'enable use of ffmpeg mpeg2 decoding', '*-*-*', none=optparse.SUPPRESS_HELP ).value grp.add_option( '--enable-ff-mpeg2', default=False, action='store_true', help=h ) + h = IfHost( 'enable use of Intel Quick Sync Video hardware acceleration', '*-*-*', none=optparse.SUPPRESS_HELP ).value + grp.add_option( '--enable-qsv', default=False, action='store_true', help=h ) + h = IfHost( 'enable OpenCL features', '*-*-*', none=optparse.SUPPRESS_HELP ).value grp.add_option( '--enable-opencl', default=False, action='store_true', help=h ) h = IfHost( 'enable HWD features', '*-*-*', none=optparse.SUPPRESS_HELP ).value grp.add_option( '--enable-hwd', default=False, action='store_true', help=h ) h = IfHost( 'enable use of fdk-aac encoder', '*-*-*', none=optparse.SUPPRESS_HELP ).value - grp.add_option( '--enable-fdk-aac', default=False, action='store_true', help=h ) + grp.add_option( '--enable-fdk-aac', dest="enable_fdk_aac", default=not host.match( '*-*-darwin*' ), action='store_true', help=h ) + grp.add_option( '--disable-fdk-aac', dest="enable_fdk_aac", action='store_false' ) + + h = IfHost( 'enable use of libav aac encoder', '*-*-*', none=optparse.SUPPRESS_HELP ).value + grp.add_option( '--enable-libav-aac', dest="enable_libav_aac", default=not host.match( '*-*-darwin*' ), action='store_true', help=h ) + grp.add_option( '--disable-libav-aac', dest="enable_libav_aac", action='store_false' ) + + h = IfHost( 'enable use of faac encoder', '*-*-*', none=optparse.SUPPRESS_HELP ).value + grp.add_option( '--enable-faac', dest="enable_faac", default=False, action='store_true', help=h ) + grp.add_option( '--disable-faac', dest="enable_faac", action='store_false' ) + + h = IfHost( 'enable use of mp4v2 muxer', '*-*-*', none=optparse.SUPPRESS_HELP ).value + grp.add_option( '--enable-mp4v2', dest="enable_mp4v2", default=True, action='store_true', help=h ) + grp.add_option( '--disable-mp4v2', dest="enable_mp4v2", action='store_false' ) + + h = IfHost( 'enable use of libmkv muxer', '*-*-*', none=optparse.SUPPRESS_HELP ).value + grp.add_option( '--enable-libmkv', dest="enable_libmkv", default=True, action='store_true', help=h ) + grp.add_option( '--disable-libmkv', dest="enable_libmkv", action='store_false' ) + + h = IfHost( 'enable use of avformat muxer', '*-*-*', none=optparse.SUPPRESS_HELP ).value + grp.add_option( '--enable-avformat', dest="enable_avformat", default=True, action='store_true', help=h ) + grp.add_option( '--disable-avformat', dest="enable_avformat", action='store_false' ) cli.add_option_group( grp ) @@ -1622,7 +1646,13 @@ int main () doc.add( 'FEATURE.gtk.mingw', int( options.enable_gtk_mingw )) doc.add( 'FEATURE.gst', int( not options.disable_gst )) doc.add( 'FEATURE.ff.mpeg2', int( options.enable_ff_mpeg2 )) - doc.add( 'FEATURE.fdk_aac', int( options.enable_fdk_aac )) + doc.add( 'FEATURE.fdk_aac', int( options.enable_fdk_aac )) + doc.add( 'FEATURE.libav_aac', int( options.enable_libav_aac )) + doc.add( 'FEATURE.faac', int( options.enable_faac )) + doc.add( 'FEATURE.mp4v2', int( options.enable_mp4v2 )) + doc.add( 'FEATURE.libmkv', int( options.enable_libmkv )) + doc.add( 'FEATURE.avformat', int( options.enable_avformat )) + doc.add( 'FEATURE.qsv', int( options.enable_qsv )) doc.add( 'FEATURE.opencl', int( options.enable_opencl )) doc.add( 'FEATURE.hwd', int( options.enable_hwd )) doc.add( 'FEATURE.xcode', int( not (Tools.xcodebuild.fail or options.disable_xcode or options.cross) )) diff --git a/make/include/main.defs b/make/include/main.defs index 45d375c36..bf6c5f4ec 100644 --- a/make/include/main.defs +++ b/make/include/main.defs @@ -43,14 +43,23 @@ ifeq (1,$(FEATURE.fdk_aac)) MODULES += contrib/fdk-aac endif +ifeq (1,$(FEATURE.faac)) + MODULES += contrib/faac +endif + +ifeq (1,$(FEATURE.mp4v2)) + MODULES += contrib/mp4v2 +endif + +ifeq (1,$(FEATURE.libmkv)) + MODULES += contrib/libmkv +endif + MODULES += contrib/lame -MODULES += contrib/faac MODULES += contrib/ffmpeg MODULES += contrib/libdvdread MODULES += contrib/libdvdnav MODULES += contrib/libbluray -MODULES += contrib/libmkv -MODULES += contrib/mp4v2 MODULES += contrib/mpeg2dec ifneq (,$(filter $(BUILD.system),mingw)) @@ -59,6 +68,10 @@ ifneq ($(HAS.pthread),1) endif endif +ifeq (1,$(FEATURE.qsv)) + MODULES += contrib/libmfx +endif + MODULES += contrib/x264 ifneq (,$(filter $(BUILD.system),cygwin mingw)) diff --git a/pkg/linux/debian/handbrake-gtk.install b/pkg/linux/debian/handbrake-gtk.install index 21f11a31e..0876fd2e8 100644 --- a/pkg/linux/debian/handbrake-gtk.install +++ b/pkg/linux/debian/handbrake-gtk.install @@ -1,4 +1,5 @@ usr/bin/ghb usr/share/applications/* usr/share/icons/* +usr/share/locale/* #DOCS# diff --git a/scripts/manicure.rb b/scripts/manicure.rb index b8be37432..83b991dd9 100755 --- a/scripts/manicure.rb +++ b/scripts/manicure.rb @@ -280,16 +280,16 @@ class Display end #Video encoder - if hash["VideoEncoder"] != "MPEG-4 (FFmpeg)" - commandString << " -e " - case hash["VideoEncoder"] - when /x264/ - commandString << "x264" - when /Theora/ - commandString << "theora" - when /MPEG/ - commandString << "ffmpeg2" - end + commandString << " -e " + case hash["VideoEncoder"] + when /x264/ + commandString << "x264" + when /Theora/ + commandString << "theora" + when /MPEG-4/ + commandString << "ffmpeg4" + when /MPEG-2/ + commandString << "ffmpeg2" end #VideoRateControl @@ -342,23 +342,23 @@ class Display when /AC3 Pass/ audioEncoders << "copy:ac3" when /AC3/ - audioEncoders << "ffac3" + audioEncoders << "ac3" when /DTS Pass/ audioEncoders << "copy:dts" when /DTS-HD Pass/ audioEncoders << "copy:dtshd" when /AAC Pass/ audioEncoders << "copy:aac" - when "AAC (FDK)" - audioEncoders << "fdk_aac" when "AAC (faac)" audioEncoders << "faac" - when "AAC (ffmpeg)" - audioEncoders << "ffaac" - when "AAC (CoreAudio)" - audioEncoders << "ca_aac" + when "AAC (ffmpeg)", "AAC (avcodec)" + audioEncoders << "av_aac" + when "AAC (FDK)" + audioEncoders << "fdk_aac" when "HE-AAC (FDK)" audioEncoders << "fdk_haac" + when "AAC (CoreAudio)" + audioEncoders << "ca_aac" when "HE-AAC (CoreAudio)" audioEncoders << "ca_haac" when /Vorbis/ @@ -366,11 +366,11 @@ class Display when /MP3 Pass/ audioEncoders << "copy:mp3" when /MP3/ - audioEncoders << "lame" - when "FLAC (ffmpeg)" - audioEncoders << "ffflac" - when "FLAC (24-bit)" - audioEncoders << "ffflac24" + audioEncoders << "mp3" + when "FLAC (ffmpeg)", "FLAC 16-bit" + audioEncoders << "flac16" + when "FLAC (24-bit)", "FLAC 24-bit" + audioEncoders << "flac24" when /Auto Pass/ audioEncoders << "copy" end @@ -467,17 +467,27 @@ class Display case hash["AudioEncoderFallback"] when /AC3/ - audioEncoderFallback << "ffac3" - when "AAC (ffmpeg)" - audioEncoderFallback << "ffaac" - when /AAC/ + audioEncoderFallback << "ac3" + when "AAC (faac)" audioEncoderFallback << "faac" + when "AAC (ffmpeg)", "AAC (avcodec)" + audioEncoderFallback << "av_aac" + when "AAC (FDK)" + audioEncoderFallback << "fdk_aac" + when "HE-AAC (FDK)" + audioEncoderFallback << "fdk_haac" + when "AAC (CoreAudio)" + audioEncoderFallback << "ca_aac" + when "HE-AAC (CoreAudio)" + audioEncoderFallback << "ca_haac" when /Vorbis/ audioEncoderFallback << "vorbis" when /MP3/ - audioEncoderFallback << "lame" - when /FLAC/ - audioEncoderFallback << "ffflac" + audioEncoderFallback << "mp3" + when "FLAC (ffmpeg)", "FLAC 16-bit" + audioEncoderFallback << "flac16" + when "FLAC (24-bit)", "FLAC 24-bit" + audioEncoderFallback << "flac24" end if audioEncoderFallback.size > 0 @@ -678,16 +688,16 @@ class Display commandString << '+ ' << hash["PresetName"] << ":" #Video encoder - if hash["VideoEncoder"] != "MPEG-4 (FFmpeg)" - commandString << " -e " - case hash["VideoEncoder"] - when /x264/ - commandString << "x264" - when /Theora/ - commandString << "theora" - when /MPEG/ - commandString << "ffmpeg2" - end + commandString << " -e " + case hash["VideoEncoder"] + when /x264/ + commandString << "x264" + when /Theora/ + commandString << "theora" + when /MPEG-4/ + commandString << "ffmpeg4" + when /MPEG-2/ + commandString << "ffmpeg2" end #VideoRateControl @@ -740,23 +750,23 @@ class Display when /AC3 Pass/ audioEncoders << "copy:ac3" when /AC3/ - audioEncoders << "ffac3" + audioEncoders << "ac3" when /DTS Pass/ audioEncoders << "copy:dts" when /DTS-HD Pass/ audioEncoders << "copy:dtshd" when /AAC Pass/ audioEncoders << "copy:aac" - when "AAC (FDK)" - audioEncoders << "fdk_aac" when "AAC (faac)" audioEncoders << "faac" - when "AAC (ffmpeg)" - audioEncoders << "ffaac" - when "AAC (CoreAudio)" - audioEncoders << "ca_aac" + when "AAC (ffmpeg)", "AAC (avcodec)" + audioEncoders << "av_aac" + when "AAC (FDK)" + audioEncoders << "fdk_aac" when "HE-AAC (FDK)" audioEncoders << "fdk_haac" + when "AAC (CoreAudio)" + audioEncoders << "ca_aac" when "HE-AAC (CoreAudio)" audioEncoders << "ca_haac" when /Vorbis/ @@ -764,11 +774,11 @@ class Display when /MP3 Pass/ audioEncoders << "copy:mp3" when /MP3/ - audioEncoders << "lame" - when "FLAC (ffmpeg)" - audioEncoders << "ffflac" - when "FLAC (24-bit)" - audioEncoders << "ffflac24" + audioEncoders << "mp3" + when "FLAC (ffmpeg)", "FLAC 16-bit" + audioEncoders << "flac16" + when "FLAC (24-bit)", "FLAC 24-bit" + audioEncoders << "flac24" when /Auto Pass/ audioEncoders << "copy" end @@ -865,17 +875,27 @@ class Display case hash["AudioEncoderFallback"] when /AC3/ - audioEncoderFallback << "ffac3" - when "AAC (ffmpeg)" - audioEncoderFallback << "ffaac" - when /AAC/ + audioEncoderFallback << "ac3" + when "AAC (faac)" audioEncoderFallback << "faac" + when "AAC (ffmpeg)", "AAC (avcodec)" + audioEncoderFallback << "av_aac" + when "AAC (FDK)" + audioEncoderFallback << "fdk_aac" + when "HE-AAC (FDK)" + audioEncoderFallback << "fdk_haac" + when "AAC (CoreAudio)" + audioEncoderFallback << "ca_aac" + when "HE-AAC (CoreAudio)" + audioEncoderFallback << "ca_haac" when /Vorbis/ audioEncoderFallback << "vorbis" when /MP3/ - audioEncoderFallback << "lame" - when /FLAC/ - audioEncoderFallback << "ffflac" + audioEncoderFallback << "mp3" + when "FLAC (ffmpeg)", "FLAC 16-bit" + audioEncoderFallback << "flac16" + when "FLAC (24-bit)", "FLAC 24-bit" + audioEncoderFallback << "flac24" end if audioEncoderFallback.size > 0 @@ -1080,16 +1100,16 @@ class Display end #Video encoder - if hash["VideoEncoder"] != "MPEG-4 (FFmpeg)" - commandString << "vcodec = " - case hash["VideoEncoder"] - when /x264/ - commandString << "HB_VCODEC_X264;\n " - when /Theora/ - commandString << "HB_VCODEC_THEORA;\n " - when /MPEG/ - commandString << "HB_VCODEC_FFMPEG_MPEG2;\n " - end + commandString << "vcodec = " + case hash["VideoEncoder"] + when /x264/ + commandString << "HB_VCODEC_X264;\n " + when /Theora/ + commandString << "HB_VCODEC_THEORA;\n " + when /MPEG-4/ + commandString << "HB_VCODEC_FFMPEG_MPEG4;\n " + when /MPEG-2/ + commandString << "HB_VCODEC_FFMPEG_MPEG2;\n " end #VideoRateControl @@ -1144,23 +1164,23 @@ class Display when /AC3 Pass/ audioEncoders << "copy:ac3" when /AC3/ - audioEncoders << "ffac3" + audioEncoders << "ac3" when /DTS Pass/ audioEncoders << "copy:dts" when /DTS-HD Pass/ audioEncoders << "copy:dtshd" when /AAC Pass/ audioEncoders << "copy:aac" - when "AAC (FDK)" - audioEncoders << "fdk_aac" when "AAC (faac)" audioEncoders << "faac" - when "AAC (ffmpeg)" - audioEncoders << "ffaac" - when "AAC (CoreAudio)" - audioEncoders << "ca_aac" + when "AAC (ffmpeg)", "AAC (avcodec)" + audioEncoders << "av_aac" + when "AAC (FDK)" + audioEncoders << "fdk_aac" when "HE-AAC (FDK)" audioEncoders << "fdk_haac" + when "AAC (CoreAudio)" + audioEncoders << "ca_aac" when "HE-AAC (CoreAudio)" audioEncoders << "ca_haac" when /Vorbis/ @@ -1168,11 +1188,11 @@ class Display when /MP3 Pass/ audioEncoders << "copy:mp3" when /MP3/ - audioEncoders << "lame" - when "FLAC (ffmpeg)" - audioEncoders << "ffflac" - when "FLAC (24-bit)" - audioEncoders << "ffflac24" + audioEncoders << "mp3" + when "FLAC (ffmpeg)", "FLAC 16-bit" + audioEncoders << "flac16" + when "FLAC (24-bit)", "FLAC 24-bit" + audioEncoders << "flac24" when /Auto Pass/ audioEncoders << "copy" end @@ -1287,27 +1307,27 @@ class Display case hash["AudioEncoderFallback"] when /AC3/ - audioEncoderFallback << "ffac3" - when "AAC (FDK)" - audioEncoderFallback << "fdk_aac" + audioEncoderFallback << "ac3" when "AAC (faac)" audioEncoderFallback << "faac" - when "AAC (ffmpeg)" - audioEncoderFallback << "ffaac" - when "AAC (CoreAudio)" - audioEncoderFallback << "ca_aac" + when "AAC (ffmpeg)", "AAC (avcodec)" + audioEncoderFallback << "av_aac" + when "AAC (FDK)" + audioEncoderFallback << "fdk_aac" when "HE-AAC (FDK)" audioEncoderFallback << "fdk_haac" + when "AAC (CoreAudio)" + audioEncoderFallback << "ca_aac" when "HE-AAC (CoreAudio)" audioEncoderFallback << "ca_haac" when /Vorbis/ audioEncoderFallback << "vorbis" when /MP3/ - audioEncoderFallback << "lame" - when "FLAC (ffmpeg)" - audioEncoderFallback << "ffflac" - when "FLAC (24-bit)" - audioEncoderFallback << "ffflac24" + audioEncoderFallback << "mp3" + when "FLAC (ffmpeg)", "FLAC 16-bit" + audioEncoderFallback << "flac16" + when "FLAC (24-bit)", "FLAC 24-bit" + audioEncoderFallback << "flac24" end if audioEncoderFallback.size > 0 @@ -1538,16 +1558,16 @@ class Display commandString << "+ " << hash["PresetName"] << ": " #Video encoder - if hash["VideoEncoder"] != "MPEG-4 (FFmpeg)" - commandString << " -e " - case hash["VideoEncoder"] - when /x264/ - commandString << "x264 " - when /Theora/ - commandString << "theora " - when /MPEG/ - commandString << "ffmpeg2 " - end + commandString << " -e " + case hash["VideoEncoder"] + when /x264/ + commandString << "x264 " + when /Theora/ + commandString << "theora " + when /MPEG-4/ + commandString << "ffmpeg4 " + when /MPEG-2/ + commandString << "ffmpeg2 " end #VideoRateControl @@ -1600,23 +1620,23 @@ class Display when /AC3 Pass/ audioEncoders << "copy:ac3" when /AC3/ - audioEncoders << "ffac3" + audioEncoders << "ac3" when /DTS Pass/ audioEncoders << "copy:dts" when /DTS-HD Pass/ audioEncoders << "copy:dtshd" when /AAC Pass/ audioEncoders << "copy:aac" - when "AAC (FDK)" - audioEncoders << "fdk_aac" when "AAC (faac)" audioEncoders << "faac" - when "AAC (ffmpeg)" - audioEncoders << "ffaac" - when "AAC (CoreAudio)" - audioEncoders << "ca_aac" + when "AAC (ffmpeg)", "AAC (avcodec)" + audioEncoders << "av_aac" + when "AAC (FDK)" + audioEncoders << "fdk_aac" when "HE-AAC (FDK)" audioEncoders << "fdk_haac" + when "AAC (CoreAudio)" + audioEncoders << "ca_aac" when "HE-AAC (CoreAudio)" audioEncoders << "ca_haac" when /Vorbis/ @@ -1624,11 +1644,11 @@ class Display when /MP3 Pass/ audioEncoders << "copy:mp3" when /MP3/ - audioEncoders << "lame" - when "FLAC (ffmpeg)" - audioEncoders << "ffflac" - when "FLAC (24-bit)" - audioEncoders << "ffflac24" + audioEncoders << "mp3" + when "FLAC (ffmpeg)", "FLAC 16-bit" + audioEncoders << "flac16" + when "FLAC (24-bit)", "FLAC 24-bit" + audioEncoders << "flac24" when /Auto Pass/ audioEncoders << "copy" end @@ -1725,17 +1745,27 @@ class Display case hash["AudioEncoderFallback"] when /AC3/ - audioEncoderFallback << "ffac3" - when "AAC (ffmpeg)" - audioEncoderFallback << "ffaac" - when /AAC/ + audioEncoderFallback << "ac3" + when "AAC (faac)" audioEncoderFallback << "faac" + when "AAC (ffmpeg)", "AAC (avcodec)" + audioEncoderFallback << "av_aac" + when "AAC (FDK)" + audioEncoderFallback << "fdk_aac" + when "HE-AAC (FDK)" + audioEncoderFallback << "fdk_haac" + when "AAC (CoreAudio)" + audioEncoderFallback << "ca_aac" + when "HE-AAC (CoreAudio)" + audioEncoderFallback << "ca_haac" when /Vorbis/ audioEncoderFallback << "vorbis" when /MP3/ - audioEncoderFallback << "lame" - when /FLAC/ - audioEncoderFallback << "ffflac" + audioEncoderFallback << "mp3" + when "FLAC (ffmpeg)", "FLAC 16-bit" + audioEncoderFallback << "flac16" + when "FLAC (24-bit)", "FLAC 24-bit" + audioEncoderFallback << "flac24" end if audioEncoderFallback.size > 0 diff --git a/test/module.defs b/test/module.defs index b7e8527c2..b7c824cf9 100644 --- a/test/module.defs +++ b/test/module.defs @@ -14,15 +14,32 @@ TEST.GCC.L = $(CONTRIB.build/)lib TEST.libs = $(LIBHB.a) TEST.GCC.l = \ - a52 ass avcodec avformat avutil avresample dvdnav dvdread faac \ - fontconfig freetype fribidi mkv mpeg2 mp3lame mp4v2 ogg \ + a52 ass avcodec avformat avutil avresample dvdnav dvdread \ + fontconfig freetype fribidi mpeg2 mp3lame ogg \ samplerate swscale theoraenc theoradec vorbis vorbisenc x264 \ bluray xml2 bz2 z +ifeq (1,$(FEATURE.qsv)) + TEST.GCC.l += mfx + TEST.GCC.D += USE_QSV HAVE_THREADS=1 +endif + ifeq (1,$(FEATURE.fdk_aac)) TEST.GCC.l += fdk-aac endif +ifeq (1,$(FEATURE.faac)) +TEST.GCC.l += faac +endif + +ifeq (1,$(FEATURE.mp4v2)) +TEST.GCC.l += mp4v2 +endif + +ifeq (1,$(FEATURE.libmkv)) +TEST.GCC.l += mkv +endif + TEST.install.exe = $(DESTDIR)$(PREFIX/)bin/$(notdir $(TEST.exe)) ############################################################################### @@ -53,6 +70,7 @@ else ifeq ($(BUILD.system),linux) TEST.GCC.l += pthread dl m else ifeq ($(BUILD.system),solaris) TEST.GCC.l += pthread nsl socket iconv + TEST.GCC.D += _POSIX_C_SOURCE=200112L __EXTENSIONS__ else ifeq (1-mingw,$(BUILD.cross)-$(BUILD.system)) ifeq ($(HAS.dlfcn),1) TEST.GCC.l += dl diff --git a/test/test.c b/test/test.c index e3a226e54..7eb109691 100644 --- a/test/test.c +++ b/test/test.c @@ -27,6 +27,10 @@ #include "parsecsv.h" #include "openclwrapper.h" +#ifdef USE_QSV +#include "qsv_common.h" +#endif + #if defined( __APPLE_CC__ ) #import <CoreServices/CoreServices.h> #include <IOKit/IOKitLib.h> @@ -135,6 +139,10 @@ static int stop_at_frame = 0; static uint64_t min_title_duration = 10; static int use_opencl = 0; static int use_hwd = 0; +#ifdef USE_QSV +static int qsv_decode = 1; +static int qsv_async_depth = -1; +#endif /* Exit cleanly on Ctrl-C */ static volatile int die = 0; @@ -1892,6 +1900,14 @@ static int HandleEvents( hb_handle_t * h ) job->vcodec = vcodec; } +#ifdef USE_QSV + if (qsv_async_depth >= 0) + { + job->qsv_async_depth = qsv_async_depth; + } + job->qsv_decode = qsv_decode; +#endif + /* Grab audio tracks */ if( atracks ) { @@ -2735,7 +2751,7 @@ static int HandleEvents( hb_handle_t * h ) } sub_config = subtitle->config; - if( mux == HB_MUX_MKV || subtitle->format == TEXTSUB) + if ((mux & HB_MUX_MASK_MKV) || subtitle->format == TEXTSUB) { sub_config.dest = PASSTHRUSUB; } @@ -3103,9 +3119,22 @@ static void ShowHelp() } if( len ) fprintf( out, "%s\n", tmp ); - fprintf( out, - " -x, --encopts <string> Specify advanced encoder options in the\n" - " same style as mencoder (x264 and ffmpeg only):\n" + fprintf(out, + " -x, --encopts <string> Specify advanced encoder options in the\n"); +#ifdef USE_QSV +if (hb_qsv_available()) +{ + fprintf(out, + " same style as mencoder (x264/qsv/ffmpeg only):\n"); +} +else +#endif +{ + fprintf(out, + " same style as mencoder (x264 and ffmpeg only):\n"); +} + + fprintf(out, " option1=value1:option2=value2\n" " --h264-profile When using x264, ensures compliance with the\n" " <string> specified H.264 profile:\n" @@ -3362,7 +3391,14 @@ static void ShowHelp() "### Filters---------------------------------------------------------\n\n" " -d, --deinterlace Deinterlace video with Libav, yadif or mcdeint\n" - " <fast/slow/slower/bob> or omitted (default settings)\n" + " <fast/slow/slower/bob"); +#ifdef USE_QSV +if (hb_qsv_available()) +{ + fprintf(out, "/qsv"); +} +#endif + fprintf( out, "> or omitted (default settings)\n" " or\n" " <YM:FD:MM:QP> (default 0:-1:-1:1)\n" " -5, --decomb Selectively deinterlaces when it detects combing\n" @@ -3445,10 +3481,22 @@ static void ShowHelp() " If \"number\" is omitted, the first srt is default.\n" " \"number\" is an 1 based index into the srt-file list\n" "\n" + ); - +#ifdef USE_QSV +if (hb_qsv_available()) +{ + fprintf( out, + "### Intel Quick Sync Video------------------------------------------------------\n\n" + " --disable-qsv-decoding Force software decoding of the video track.\n" + " --qsv-async-depth Specifies how many asynchronous operations should be\n" + " performed before the result is explicitly synchronized.\n" + " Default: 4. If zero, the value is not specified.\n" + "\n" ); } +#endif +} /**************************************************************************** * ShowPresets: @@ -3591,7 +3639,9 @@ static int ParseOptions( int argc, char ** argv ) #define NO_OPENCL 287 #define NORMALIZE_MIX 288 #define AUDIO_DITHER 289 - + #define QSV_BASELINE 289 + #define QSV_ASYNC_DEPTH 290 + for( ;; ) { static struct option long_options[] = @@ -3601,7 +3651,13 @@ static int ParseOptions( int argc, char ** argv ) { "verbose", optional_argument, NULL, 'v' }, { "no-dvdnav", no_argument, NULL, DVDNAV }, { "no-opencl", no_argument, NULL, NO_OPENCL }, - + +#ifdef USE_QSV + { "qsv-baseline", no_argument, NULL, QSV_BASELINE }, + { "qsv-async-depth", required_argument, NULL, QSV_ASYNC_DEPTH }, + { "disable-qsv-decoding", no_argument, &qsv_decode, 0 }, +#endif + { "format", required_argument, NULL, 'f' }, { "input", required_argument, NULL, 'i' }, { "output", required_argument, NULL, 'o' }, @@ -4228,6 +4284,21 @@ static int ParseOptions( int argc, char ** argv ) case MIN_DURATION: min_title_duration = strtol( optarg, NULL, 0 ); break; +#ifdef USE_QSV + case QSV_BASELINE: + if (hb_qsv_available()) + { + /* XXX: for testing workarounds */ + hb_qsv_info->capabilities &= ~HB_QSV_CAP_MSDK_API_1_6; + hb_qsv_info->capabilities &= ~HB_QSV_CAP_OPTION2_BRC; + hb_qsv_info->capabilities &= ~HB_QSV_CAP_OPTION2_TRELLIS; + hb_qsv_info->capabilities &= ~HB_QSV_CAP_OPTION2_LOOKAHEAD; + } + break; + case QSV_ASYNC_DEPTH: + qsv_async_depth = atoi(optarg); + break; +#endif default: fprintf( stderr, "unknown option (%s)\n", argv[cur_optind] ); return -1; |