来源:https://github.com/galad87/HandBrake-QuickSync-Mac/commit/2c1332958f7095c640cbcbcb45ffc955739d5945#diff-72d938f71df3506b8ad74530b39e7a0bR83
Skip to content
QuickSync encoder via VideoToolbox
Implements a new encoder in HandBrake that uses VideoToolbox.framework
to access the hardware h.264 encoder.
1 parent
a13430b commit 2c1332958f7095c640cbcbcb45ffc955739d5945
galad87 committed on 20 Jun 2013
Showing
with 540 additions and 14 deletions.
- +10 −8
@@ -185,15 +185,16 @@ hb_encoder_t *hb_video_encoders_last_item = NULL; |
hb_encoder_internal_t hb_video_encoders[] = |
// 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, }, |
+ { { "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, }, |
- { { "H.264 (x264)", "x264", HB_VCODEC_X264, 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, }, |
+ { { "H.264 (x264)", "x264", HB_VCODEC_X264, HB_MUX_MASK_MP4|HB_MUX_MASK_MKV, }, NULL, 1, HB_GID_VCODEC_H264, }, |
+ { { "H.264 (VideoToolbox)", "h264", HB_VCODEC_VT_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) |
@@ -202,6 +203,7 @@ static int hb_video_encoder_is_enabled(int encoder) |
// the following encoders are always enabled |
+ case HB_VCODEC_VT_H264: |
case HB_VCODEC_FFMPEG_MPEG4: |
case HB_VCODEC_FFMPEG_MPEG2: |
@@ -403,6 +403,7 @@ struct hb_job_s |
#define HB_VCODEC_MASK 0x00000FF |
#define HB_VCODEC_X264 0x0000001 |
#define HB_VCODEC_THEORA 0x0000002 |
+#define HB_VCODEC_VT_H264 0x0000004 |
#define HB_VCODEC_FFMPEG_MPEG4 0x0000010 |
#define HB_VCODEC_FFMPEG_MPEG2 0x0000020 |
#define HB_VCODEC_FFMPEG_MASK 0x00000F0 |
@@ -1008,6 +1009,7 @@ extern hb_work_object_t hb_encvorbis; |
extern hb_work_object_t hb_muxer; |
extern hb_work_object_t hb_encca_aac; |
extern hb_work_object_t hb_encca_haac; |
+extern hb_work_object_t hb_encvt_h264; |
extern hb_work_object_t hb_encavcodeca; |
extern hb_work_object_t hb_reader; |
@@ -1644,6 +1644,7 @@ int hb_global_init() |
hb_register(&hb_encca_aac);
|
hb_register(&hb_encca_haac);
|
+ hb_register(&hb_encvt_h264);
|
hb_register(&hb_encfaac);
|
@@ -97,6 +97,7 @@ static int MKVInit( hb_mux_object_t * m ) |
+ case HB_VCODEC_VT_H264:
|
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;
|
@@ -129,7 +129,7 @@ static int MP4Init( hb_mux_object_t * m ) |
- if( job->vcodec == HB_VCODEC_X264 )
|
+ if( job->vcodec == HB_VCODEC_X264 || job->vcodec == HB_VCODEC_VT_H264 )
|
/* Stolen from mp4creator */
|
MP4SetVideoProfileLevel( m->file, 0x7F );
|
@@ -684,7 +684,7 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, |
if( mux_data == job->mux_data )
|
- if( job->vcodec == HB_VCODEC_X264 ||
|
+ if( job->vcodec == HB_VCODEC_X264 || job->vcodec == HB_VCODEC_VT_H264 ||
|
( job->vcodec & HB_VCODEC_FFMPEG_MASK ) )
|
if ( buf && buf->s.start < buf->s.renderOffset )
|
@@ -706,7 +706,7 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, |
stop = buf->s.start + buf->s.duration;
|
- if( job->vcodec == HB_VCODEC_X264 ||
|
+ if( job->vcodec == HB_VCODEC_X264 || job->vcodec == HB_VCODEC_VT_H264 ||
|
( job->vcodec & HB_VCODEC_FFMPEG_MASK ) )
|
// x264 supplies us with DTS, so offset is PTS - DTS
|
@@ -744,7 +744,7 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, |
- if( job->vcodec == HB_VCODEC_X264 ||
|
+ if( job->vcodec == HB_VCODEC_X264 || job->vcodec == HB_VCODEC_VT_H264 ||
|
( job->vcodec & HB_VCODEC_FFMPEG_MASK ) )
|
// x264 supplies us with DTS
|
@@ -822,7 +822,7 @@ 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 ||
|
+ if( ( job->vcodec == HB_VCODEC_X264 || job->vcodec == HB_VCODEC_VT_H264||
|
( job->vcodec & HB_VCODEC_FFMPEG_MASK ) )
|
&& mux_data == job->mux_data )
|
498
libhb/platform/macosx/encvt_h264.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 <VideoToolbox/VideoToolbox.h>
|
+#include <CoreMedia/CoreMedia.h>
|
+#include <CoreVideo/CoreVideo.h>
|
+int encvt_h264Init( hb_work_object_t *, hb_job_t * );
|
+int encvt_h264Work( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** );
|
+void encvt_h264Close( hb_work_object_t * );
|
+hb_work_object_t hb_encvt_h264 =
|
+ "H.264 encoder (VideoToolbox)",
|
+struct hb_work_private_s
|
+ VTCompressionSessionRef session;
|
+ CMSimpleQueueRef queue;
|
+ int chap_mark; // saved chap mark when we're propagating it
|
+void pixelBufferReleasePlanarBytesCallback( void *releaseRefCon, const void *dataPtr, size_t dataSize, size_t numberOfPlanes, const void *planeAddresses[] )
|
+ hb_buffer_t * buf = (hb_buffer_t *) releaseRefCon;
|
+ hb_buffer_close( &buf );
|
+void pixelBufferReleaseBytesCallback( void *releaseRefCon, const void *baseAddress )
|
+ free( (void *) baseAddress );
|
+void myVTCompressionOutputCallback(
|
+void *outputCallbackRefCon,
|
+void *sourceFrameRefCon,
|
+VTEncodeInfoFlags infoFlags,
|
+CMSampleBufferRef sampleBuffer )
|
+ CVPixelBufferRef pixelbuffer = sourceFrameRefCon;
|
+ CVPixelBufferRelease(pixelbuffer);
|
+ hb_log("VTCompressionSession: myVTCompressionOutputCallback called error");
|
+ CFRetain(sampleBuffer);
|
+ CMSimpleQueueRef queue = outputCallbackRefCon;
|
+ err = CMSimpleQueueEnqueue(queue, sampleBuffer);
|
+ hb_log("VTCompressionSession: myVTCompressionOutputCallback queue full");
|
+OSStatus initVTSession(hb_work_object_t * w, hb_job_t * job, hb_work_private_t * pv)
|
+ CFStringRef key = kVTVideoEncoderSpecification_EncoderID;
|
+ CFStringRef value = CFSTR("com.apple.videotoolbox.videoencoder.h264.gva");
|
+ CFStringRef bkey = CFSTR("EnableHardwareAcceleratedVideoEncoder");
|
+ CFBooleanRef bvalue = kCFBooleanTrue;
|
+ CFStringRef ckey = CFSTR("RequireHardwareAcceleratedVideoEncoder");
|
+ CFBooleanRef cvalue = kCFBooleanTrue;
|
+ CFMutableDictionaryRef encoderSpecifications = CFDictionaryCreateMutable(
|
+ &kCFTypeDictionaryKeyCallBacks,
|
+ &kCFTypeDictionaryValueCallBacks);
|
+ // Comment out to disable QuickSync
|
+ CFDictionaryAddValue(encoderSpecifications, bkey, bvalue);
|
+ CFDictionaryAddValue(encoderSpecifications, ckey, cvalue);
|
+ CFDictionaryAddValue(encoderSpecifications, key, value);
|
+ err = VTCompressionSessionCreate(
|
+ kCMVideoCodecType_H264,
|
+ &myVTCompressionOutputCallback,
|
+ hb_log("Error creating a VTCompressionSession err=%"PRId64"", (int64_t)err);
|
+ err = VTSessionSetProperty(pv->session, kVTCompressionPropertyKey_AllowFrameReordering, kCFBooleanTrue);
|
+ hb_log("VTSessionSetProperty: kVTCompressionPropertyKey_AllowFrameReordering failed");
|
+ const int maxKeyFrameInterval = 10 * 30;
|
+ err = VTSessionSetProperty(pv->session, kVTCompressionPropertyKey_MaxKeyFrameInterval,
|
+ CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &maxKeyFrameInterval));
|
+ hb_log("VTSessionSetProperty: kVTCompressionPropertyKey_MaxKeyFrameInterval failed");
|
+ const int maxFrameDelayCount = 24;
|
+ err = VTSessionSetProperty(pv->session, kVTCompressionPropertyKey_MaxFrameDelayCount,
|
+ CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &maxFrameDelayCount));
|
+ hb_log("VTSessionSetProperty: kVTCompressionPropertyKey_MaxKeyFrameInterval failed");
|
+ const int frameRate = (int)( (double)job->vrate / (double)job->vrate_base + 0.5 );
|
+ err = VTSessionSetProperty(pv->session, kVTCompressionPropertyKey_ExpectedFrameRate,
|
+ CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &frameRate));
|
+ hb_log("VTSessionSetProperty: kVTCompressionPropertyKey_ExpectedFrameRate failed");
|
+ if( job->vquality < 0 )
|
+ const int averageBitRate = job->vbitrate * 1024;
|
+ err = VTSessionSetProperty(pv->session, kVTCompressionPropertyKey_AverageBitRate,
|
+ CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &averageBitRate));
|
+ hb_log("VTSessionSetProperty: kVTCompressionPropertyKey_AverageBitRate failed");
|
+ err = VTSessionSetProperty(pv->session, kVTCompressionPropertyKey_ProfileLevel, kVTProfileLevel_H264_High_5_0);
|
+ hb_log("VTSessionSetProperty: kVTCompressionPropertyKey_ProfileLevel failed");
|
+ CFRelease(encoderSpecifications);
|
+void setupMagicCookie(hb_work_object_t * w, hb_job_t * job, hb_work_private_t * pv)
|
+ CMFormatDescriptionRef format = NULL;
|
+ err = initVTSession(w, job, pv);
|
+ size_t rgbBufSize = sizeof(uint8) * 3 * job->width * job->height;
|
+ uint8 *rgbBuf = malloc(rgbBufSize);
|
+ // Compress a random frame to get the magicCookie
|
+ CVPixelBufferRef pxbuffer = NULL;
|
+ CVPixelBufferCreateWithBytes(kCFAllocatorDefault,
|
+ kCVPixelFormatType_24RGB,
|
+ &pixelBufferReleaseBytesCallback,
|
+ if (kCVReturnSuccess != err)
|
+ hb_log("VTCompressionSession: CVPixelBuffer error");
|
+ CMTime pts = CMTimeMake(0, 90000);
|
+ err = VTCompressionSessionEncodeFrame(
|
+ VTCompressionSessionCompleteFrames(pv->session, CMTimeMake(0,90000));
|
+ CMSampleBufferRef sampleBuffer = (CMSampleBufferRef) CMSimpleQueueDequeue(pv->queue);
|
+ format = CMSampleBufferGetFormatDescription(sampleBuffer);
|
+ hb_log("VTCompressionSession: Format Description error");
|
+ CFDictionaryRef extentions = CMFormatDescriptionGetExtensions(format);
|
+ hb_log("VTCompressionSession: Format Description Extensions error");
|
+ CFDictionaryRef atoms = CFDictionaryGetValue(extentions, kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms);
|
+ CFDataRef magicCookie = CFDictionaryGetValue(atoms, CFSTR("avcC"));
|
+ hb_log("VTCompressionSession: Magic Cookie error");
|
+ const uint8_t *avcCAtom = CFDataGetBytePtr(magicCookie);
|
+ int8_t spsCount = (avcCAtom[5] & 0x1f);
|
+ for (i = 0; i < spsCount; i++) {
|
+ uint16_t spsSize = (avcCAtom[ptrPos++] << 8) & 0xff00;
|
+ spsSize += avcCAtom[ptrPos++] & 0xff;
|
+ memcpy(w->config->h264.sps + spsPos, avcCAtom+ptrPos, spsSize);;
|
+ w->config->h264.sps_length = spsPos;
|
+ int8_t ppsCount = avcCAtom[ptrPos++];
|
+ for (i = 0; i < ppsCount; i++) {
|
+ uint16_t ppsSize = (avcCAtom[ptrPos++] << 8) & 0xff00;
|
+ ppsSize += avcCAtom[ptrPos++] & 0xff;
|
+ memcpy(w->config->h264.pps + ppsPos, avcCAtom+ptrPos, ppsSize);;
|
+ w->config->h264.pps_length = ppsPos;
|
+ VTCompressionSessionInvalidate(pv->session);
|
+ CFRelease(pv->session);
|
+ CFRelease(sampleBuffer);
|
+int encvt_h264Init( hb_work_object_t * w, hb_job_t * job )
|
+ hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );
|
+ setupMagicCookie(w, job, pv);
|
+ err = initVTSession(w, job, pv);
|
+ hb_log("Error creating a VTCompressionSession err=%"PRId64"", (int64_t)err);
|
+/***********************************************************************
|
+ ***********************************************************************
|
+ **********************************************************************/
|
+void encvt_h264Close( hb_work_object_t * w )
|
+ hb_work_private_t * pv = w->private_data;
|
+ VTCompressionSessionInvalidate(pv->session);
|
+ CFRelease(pv->session);
|
+ w->private_data = NULL;
|
+/***********************************************************************
|
+ ***********************************************************************
|
+ **********************************************************************/
|
+hb_buffer_t* extractData(CMSampleBufferRef sampleBuffer, hb_work_object_t * w)
|
+ hb_work_private_t * pv = w->private_data;
|
+ hb_job_t * job = pv->job;
|
+ hb_buffer_t *buf = NULL;
|
+ CMItemCount samplesNum = CMSampleBufferGetNumSamples(sampleBuffer);
|
+ hb_log("VTCompressionSession: more than 1 sample in sampleBuffer = %ld", samplesNum);
|
+ CMBlockBufferRef buffer = CMSampleBufferGetDataBuffer(sampleBuffer);
|
+ size_t sampleSize = CMBlockBufferGetDataLength(buffer);
|
+ buf = hb_buffer_init( sampleSize );
|
+ err = CMBlockBufferCopyDataBytes(buffer, 0, sampleSize, buf->data);
|
+ if (err != kCMBlockBufferNoErr)
|
+ hb_log("VTCompressionSession: CMBlockBufferCopyDataBytes error");
|
+ buf->s.frametype = HB_FRAME_IDR;
|
+ buf->s.flags |= HB_FRAME_REF;
|
+ CFArrayRef attachmentsArray = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, 0);
|
+ if (CFArrayGetCount(attachmentsArray))
|
+ CFDictionaryRef dict = CFArrayGetValueAtIndex(attachmentsArray, 0);
|
+ if (CFDictionaryGetValueIfPresent(dict, kCMSampleAttachmentKey_NotSync, NULL))
|
+ if (CFDictionaryGetValueIfPresent(dict, kCMSampleAttachmentKey_PartialSync, NULL))
|
+ buf->s.frametype = HB_FRAME_I;
|
+ else if (CFDictionaryGetValueIfPresent(dict, kCMSampleAttachmentKey_IsDependedOnByOthers,(const void **) &b))
|
+ Boolean bv = CFBooleanGetValue(b);
|
+ buf->s.frametype = HB_FRAME_P;
|
+ buf->s.frametype = HB_FRAME_B;
|
+ buf->s.flags &= ~HB_FRAME_REF;
|
+ buf->s.frametype = HB_FRAME_P;
|
+ CMTime decodeTimeStamp = CMSampleBufferGetDecodeTimeStamp(sampleBuffer);
|
+ CMTime presentationTimeStamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
|
+ if ( !w->config->h264.init_delay && presentationTimeStamp.value )
|
+ w->config->h264.init_delay = presentationTimeStamp.value;
|
+ buf->f.width = job->width;
|
+ buf->f.height = job->height;
|
+ buf->s.start = presentationTimeStamp.value + w->config->h264.init_delay;
|
+ buf->s.stop = presentationTimeStamp.value + w->config->h264.init_delay;
|
+ buf->s.renderOffset = decodeTimeStamp.value;
|
+ /* 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
|
+ if( buf->s.frametype == HB_FRAME_IDR && pv->next_chap != 0 && pv->next_chap <= presentationTimeStamp.value )
|
+ buf->s.new_chap = pv->chap_mark;
|
+int encvt_h264Work( 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 = NULL;
|
+ CMSampleBufferRef sampleBuffer = NULL;
|
+ // EOF on input. Flush any frames still in the decoder then
|
+ // send the eof downstream to tell the muxer we're done.
|
+ VTCompressionSessionCompleteFrames(pv->session, kCMTimeInvalid);
|
+ hb_buffer_t *last_buf = NULL;
|
+ while ( ( sampleBuffer = (CMSampleBufferRef) CMSimpleQueueDequeue(pv->queue) ) )
|
+ buf = extractData(sampleBuffer, w);
|
+ CFRelease(sampleBuffer);
|
+ if ( last_buf == NULL )
|
+ // Flushed everything - add the eof to the end of the chain.
|
+ if ( last_buf == NULL )
|
+ // Create a CVPixelBuffer to wrap the frame data
|
+ CVPixelBufferRef pxbuffer = NULL;
|
+ hb_buffer_t *in_c = hb_buffer_dup(in);
|
+ void *planeBaseAddress[3] = {in_c->plane[0].data, in_c->plane[1].data, in_c->plane[2].data};
|
+ size_t planeWidth[3] = {in_c->plane[0].width, in_c->plane[1].width, in_c->plane[2].width};
|
+ size_t planeHeight[3] = {in_c->plane[0].height, in_c->plane[1].height, in_c->plane[2].height};
|
+ size_t planeBytesPerRow[3] = {in_c->plane[0].stride, in_c->plane[1].stride, in_c->plane[2].stride};
|
+ err = CVPixelBufferCreateWithPlanarBytes(
|
+ kCVPixelFormatType_420YpCbCr8Planar,
|
+ &pixelBufferReleasePlanarBytesCallback,
|
+ if (kCVReturnSuccess != err)
|
+ hb_log("VTCompressionSession: CVPixelBuffer error");
|
+ CFDictionaryRef frameProperties = NULL;
|
+ if( in->s.new_chap && job->chapter_markers )
|
+ /* chapters have to start with an IDR frame so request that this
|
+ frame be coded as IDR. Since there may be up to 16 frames
|
+ currently 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. */
|
+ const void *keys[1] = { kVTEncodeFrameOptionKey_ForceKeyFrame };
|
+ const void *values[1] = { kCFBooleanTrue };
|
+ frameProperties = CFDictionaryCreate(NULL, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
+ if( pv->next_chap == 0 )
|
+ pv->next_chap = in->s.start;
|
+ pv->chap_mark = in->s.new_chap;
|
+ /* don't let 'work_loop' put a chapter mark on the wrong buffer */
|
+ // Send the frame to be encoded
|
+ err = VTCompressionSessionEncodeFrame(
|
+ CMTimeMake(in->s.start, 90000),
|
+ hb_log("VTCompressionSession: VTCompressionSessionEncodeFrame error");
|
+ CFRelease(frameProperties);
|
+ // Return a frame if ready
|
+ sampleBuffer = (CMSampleBufferRef) CMSimpleQueueDequeue(pv->queue);
|
+ buf = extractData(sampleBuffer, w);
|
+ CFRelease(sampleBuffer);
|
@@ -1027,6 +1027,9 @@ static void do_job(hb_job_t *job) |
w = hb_get_work( WORK_ENCX264 );
|
+ case HB_VCODEC_VT_H264:
|
+ w = hb_get_work( WORK_ENCVT_H264 );
|
w = hb_get_work( WORK_ENCTHEORA );
|
18
macosx/HandBrake.xcodeproj/project.pbxproj
27D6C77314B102DA00B785E4 /* libxml2.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D6C74014B102DA00B785E4 /* libxml2.a */; };
|
3490BCB41614CF8D002A5AD7 /* HandBrake.icns in Resources */ = {isa = PBXBuildFile; fileRef = 3490BCB31614CF8D002A5AD7 /* HandBrake.icns */; };
|
46AB433515F98A2B009C0961 /* DockTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 46AB433415F98A2B009C0961 /* DockTextField.m */; };
|
+ A90156C21770AB9200079F5A /* VideoToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A90156C11770AB9200079F5A /* VideoToolbox.framework */; };
|
+ A90156C31770ADCE00079F5A /* VideoToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A90156C11770AB9200079F5A /* VideoToolbox.framework */; };
|
+ A94BC59D1770C0110055F56B /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A94BC59C1770C0110055F56B /* CoreMedia.framework */; };
|
+ A94BC59E1770C0180055F56B /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A94BC59C1770C0110055F56B /* CoreMedia.framework */; };
|
+ A94BC5A01770C0C00055F56B /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A94BC59F1770C0C00055F56B /* CoreVideo.framework */; };
|
+ A94BC5A11770C0C70055F56B /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A94BC59F1770C0C00055F56B /* CoreVideo.framework */; };
|
A9E1467B16BC2ABD00C307BC /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A9E1467A16BC2ABD00C307BC /* QuartzCore.framework */; };
|
A9E1468016BC2AD800C307BC /* next-p.pdf in Resources */ = {isa = PBXBuildFile; fileRef = A9E1467C16BC2AD800C307BC /* next-p.pdf */; };
|
A9E1468116BC2AD800C307BC /* pause-p.pdf in Resources */ = {isa = PBXBuildFile; fileRef = A9E1467D16BC2AD800C307BC /* pause-p.pdf */; };
|
34FF2FC014EEC363004C2400 /* HBAdvancedController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBAdvancedController.h; sourceTree = "<group>"; };
|
46AB433315F98A2B009C0961 /* DockTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DockTextField.h; sourceTree = "<group>"; };
|
46AB433415F98A2B009C0961 /* DockTextField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DockTextField.m; sourceTree = "<group>"; };
|
+ A90156C11770AB9200079F5A /* VideoToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = VideoToolbox.framework; path = /System/Library/Frameworks/VideoToolbox.framework; sourceTree = "<absolute>"; };
|
+ A94BC59C1770C0110055F56B /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = /System/Library/Frameworks/CoreMedia.framework; sourceTree = "<absolute>"; };
|
+ A94BC59F1770C0C00055F56B /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = /System/Library/Frameworks/CoreVideo.framework; sourceTree = "<absolute>"; };
|
A9E1467A16BC2ABD00C307BC /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = /System/Library/Frameworks/QuartzCore.framework; sourceTree = "<absolute>"; };
|
A9E1467C16BC2AD800C307BC /* next-p.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = "next-p.pdf"; sourceTree = "<group>"; };
|
A9E1467D16BC2AD800C307BC /* pause-p.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = "pause-p.pdf"; sourceTree = "<group>"; };
|
isa = PBXFrameworksBuildPhase;
|
buildActionMask = 2147483647;
|
+ A94BC5A11770C0C70055F56B /* CoreVideo.framework in Frameworks */,
|
+ A94BC59D1770C0110055F56B /* CoreMedia.framework in Frameworks */,
|
+ A90156C31770ADCE00079F5A /* VideoToolbox.framework in Frameworks */,
|
273F203014ADB9790021BE6D /* AudioToolbox.framework in Frameworks */,
|
273F202314ADB8650021BE6D /* IOKit.framework in Frameworks */,
|
273F203314ADB9F00021BE6D /* CoreServices.framework in Frameworks */,
|
isa = PBXFrameworksBuildPhase;
|
buildActionMask = 2147483647;
|
+ A94BC5A01770C0C00055F56B /* CoreVideo.framework in Frameworks */,
|
+ A94BC59E1770C0180055F56B /* CoreMedia.framework in Frameworks */,
|
+ A90156C21770AB9200079F5A /* VideoToolbox.framework in Frameworks */,
|
A9E1467B16BC2ABD00C307BC /* QuartzCore.framework in Frameworks */,
|
273F21C114ADE7A20021BE6D /* Growl.framework in Frameworks */,
|
273F21C214ADE7BC0021BE6D /* Sparkle.framework in Frameworks */,
|
273F203414ADBAC30021BE6D /* Frameworks */ = {
|
+ A94BC59F1770C0C00055F56B /* CoreVideo.framework */,
|
+ A94BC59C1770C0110055F56B /* CoreMedia.framework */,
|
+ A90156C11770AB9200079F5A /* VideoToolbox.framework */,
|
A9E1467A16BC2ABD00C307BC /* QuartzCore.framework */,
|
273F20C714ADC4FF0021BE6D /* QTKit.framework */,
|
273F202F14ADB9790021BE6D /* AudioToolbox.framework */,
|
@@ -50,7 +50,7 @@ BUILD.out += $(TEST.install.exe) |
TEST.GCC.I += $(LIBHB.GCC.I)
|
ifeq ($(BUILD.system),darwin)
|
- TEST.GCC.f += IOKit CoreServices AudioToolbox
|
+ TEST.GCC.f += IOKit CoreServices AudioToolbox VideoToolbox CoreMedia CoreVideo
|
else ifeq ($(BUILD.system),linux)
|
TEST.GCC.l += pthread dl m
|
0 comments
on commit 2c13329
You’re not receiving notifications from this thread.
- 重新想象 Windows 8 Store Apps (29) - 图片处理
原文:重新想象 Windows 8 Store Apps (29) - 图片处理 [源码下载] 重新想象 Windows 8 Store Apps (29) - 图片处理 作者:webabcd介绍重新 ...
- Feign源码解析系列-注册套路
感谢不知名朋友的打赏,感谢你的支持! 开始 在追寻Feign源码的过程中发现了一些套路,既然是套路,就可以举一反三,所以值得关注. 这篇会详细解析Feign Client配置和初始化的方式,这些方式大 ...
- xml中“ < > ”转义为“ < > ”问题处理
曾经也碰到过类似问题,解决方法是在发送或者解析报文前执行上面的方法将内容转义一下,现在我用dom4j组装如下的报文(报文体中内容传输时加密处理),大致介绍一下上面方法的使用,具体看代码. import ...
- Base64加密工具
正常来讲加密基本上永远都要伴随着解密,所谓的加密或者解密,往往都需要有一些规则,在JDK1.8开始,提供有新的加密处理操作类,Base64处理类--Base64类 在该类之中存在两个内部类:Base6 ...
- 【机器学习基础】无监督学习(3)——AutoEncoder
前面主要回顾了无监督学习中的三种降维方法,本节主要学习另一种无监督学习AutoEncoder,这个方法在无监督学习领域应用比较广泛,尤其是其思想比较通用. AutoEncoder 0.AutoEnco ...
- mac安装office2011,提示无法打开文件Normal.dotm,因为内容有错误
最近使用mac上的office,发现一个问题,每次打开office11都会报错,提示“无法打开文件Normal.dotm,因为内容有错误”,于是就在网络上搜索了一下,找到如下一段话, I just f ...
- Mac下显示隐藏文件 以及修改 hosts文件内容
修改hosts 文件内容: 进入etc 文件夹,找到hosts 文件,把该文件复制出来,修改完里面的内容后,先把etc中的hosts 文件删除,然后在把修改后的文件脱机去 可能需要管理员的密码,你输入 ...
- mac 连接windows 共享内容
mac 连接windows 共享内容 一:场景 在win7上下载了一个5G左右的系统文件,想弄到mac上,本打算用使用U盘,把文件从win7copy到mac电脑上: 可是U盘的分区是fat的,大于4G ...
- mac中的word内容丢失
改了一晚上好不容易快搞完了,结果1万字的内容丢了,并且不知道自己当时怎么想的还清理了回收站 还是用mac自带的工具吧,同时代码也要及时上传github
随机推荐
- FastDfs的搭建
一.什么是FastDFS FastDFS是用c语言编写的一款开源的分布式文件系统.FastDFS为互联网量身定制,充分考虑了冗余备份.负载均衡.线性扩容等机制,并注重高可用.高性能等指标,使用Fast ...
- 【oracle】迁表结构和数据
背景:把一些表和数据从某库迁到另一个库 1.命令框: exp yktsh/yktsh_2019@orcl30 file=d:\yktsh20191201.dmp log=d:\daochu; exp ...
- 7.Vue的计算属性
1.什么是计算属性 computed:计算属性的重点突出在 属性 两个字上(属性是名词),首先它是个 属性 其次这个属性有 计算的能力(计算是动词),这里的 计算 就是个函数:简单点说,它就是一个能够 ...
- 怎样删掉vc++ 对话框中的蓝色虚线框
选择"格式"--"切换辅助线"或者是快捷键alt+o , g
- Linux性能优化实战学习笔记:第六讲
一.环境准备 1.安装软件包 终端1 机器配置:2 CPU,8GB 内存 预先安装 docker.sysstat.perf等工具 [root@luoahong ~]# docker -v Docker ...
- 配置中心Apollo实战
Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境.不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限.流程治理等特性,适用于微服务配置管理场景. 服 ...
- springcloud(六,多个服务提供者)
spring cloud (一.服务注册demo_eureka) spring cloud (二.服务注册安全demo_eureka) spring cloud (三.服务提供者demo_provid ...
- Java软件生产监控工具Btrace的使用
Btrace BTrace是sun公司推出的一款Java 动态.安全追踪(监控)工具,可以在不用重启的情况下监控系统运行情况,方便的获取程序运行时的数据信息,如方法参数.返回值.全局变量和堆栈信息等, ...
- 使用Shell上传/下载文件
来源:https://www.cnblogs.com/pcyy/p/7568820.html 1,安装lrzsz工具包 yum install lrzsz 2,安装完成后 输入rz选择文件进行上传
- alicebot
一. 为什么Alice不支持中文因为Alice的question都会被bitoflife.chatterbean.text.Transformations类中的fit函数过滤,而过滤的表达式就是: ...