HandBrake-QuickSync-Mac (内容:QuickSync encoder via VideoToolbox )

来源:https://github.com/galad87/HandBrake-QuickSync-Mac/commit/2c1332958f7095c640cbcbcb45ffc955739d5945#diff-72d938f71df3506b8ad74530b39e7a0bR83

Skip to content

This repository

  •  

galad87/HandBrake-QuickSync-Mac

forked from kallisti5/HaikuBrake

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.

  1. +10 −8 ?????
  1. test/module.defs

18 ????? libhb/common.c

@@ -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, },
 
// 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", "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_X264:
 
+ case HB_VCODEC_VT_H264:
 
case HB_VCODEC_THEORA:
 
case HB_VCODEC_FFMPEG_MPEG4:
 
case HB_VCODEC_FFMPEG_MPEG2:
 

2 ????? libhb/common.h

@@ -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;
 
 

1 ?????

libhb/hb.c

@@ -1644,6 +1644,7 @@ int hb_global_init()
 

#ifdef __APPLE__

 

hb_register(&hb_encca_aac);

 

hb_register(&hb_encca_haac);

 

+ hb_register(&hb_encvt_h264);

 

#endif

 

#ifdef USE_FAAC

 

hb_register(&hb_encfaac);

 

1 ?????

libhb/internal.h

@@ -406,6 +406,7 @@ enum
 

WORK_ENCAVCODEC,

 

WORK_ENCX264,

 

WORK_ENCTHEORA,

 

+ WORK_ENCVT_H264,

 

WORK_DECA52,

 

WORK_DECAVCODEC,

 

WORK_DECAVCODECV,

 

1 ?????

libhb/muxmkv.c

@@ -97,6 +97,7 @@ static int MKVInit( hb_mux_object_t * m )
 

switch (job->vcodec)

 

{

 

case HB_VCODEC_X264:

 

+ 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;

 

10 ?????

libhb/muxmp4.c

@@ -129,7 +129,7 @@ static int MP4Init( hb_mux_object_t * m )
 

return 0;

 

}

 
 

- 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 )

 

{

 

/* Video */

 

- 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

@@ -0,0 +1,498 @@
 

+/* 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 "hb.h"

 

+#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 =

 

+{

 

+ WORK_ENCVT_H264,

 

+ "H.264 encoder (VideoToolbox)",

 

+ encvt_h264Init,

 

+ encvt_h264Work,

 

+ encvt_h264Close

 

+};

 

+

 

+struct hb_work_private_s

 

+{

 

+ hb_job_t * job;

 

+

 

+ VTCompressionSessionRef session;

 

+ CMSimpleQueueRef queue;

 

+

 

+ int chap_mark; // saved chap mark when we‘re propagating it

 

+ int64_t next_chap;

 

+};

 

+

 

+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,

 

+OSStatus status,

 

+VTEncodeInfoFlags infoFlags,

 

+CMSampleBufferRef sampleBuffer )

 

+{

 

+ OSStatus err;

 

+

 

+ if (sourceFrameRefCon)

 

+ {

 

+ CVPixelBufferRef pixelbuffer = sourceFrameRefCon;

 

+ CVPixelBufferRelease(pixelbuffer);

 

+ }

 

+

 

+ if (status != noErr)

 

+ {

 

+ hb_log("VTCompressionSession: myVTCompressionOutputCallback called error");

 

+ }

 

+ else

 

+ {

 

+ CFRetain(sampleBuffer);

 

+ CMSimpleQueueRef queue = outputCallbackRefCon;

 

+ err = CMSimpleQueueEnqueue(queue, sampleBuffer);

 

+ if (err)

 

+ hb_log("VTCompressionSession: myVTCompressionOutputCallback queue full");

 

+ }

 

+}

 

+

 

+OSStatus initVTSession(hb_work_object_t * w, hb_job_t * job, hb_work_private_t * pv)

 

+{

 

+ OSStatus err = noErr;

 

+

 

+ 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(

 

+ kCFAllocatorDefault,

 

+ 3,

 

+ &kCFTypeDictionaryKeyCallBacks,

 

+ &kCFTypeDictionaryValueCallBacks);

 

+

 

+ // Comment out to disable QuickSync

 

+ CFDictionaryAddValue(encoderSpecifications, bkey, bvalue);

 

+ CFDictionaryAddValue(encoderSpecifications, ckey, cvalue);

 

+ CFDictionaryAddValue(encoderSpecifications, key, value);

 

+

 

+ err = VTCompressionSessionCreate(

 

+ kCFAllocatorDefault,

 

+ job->width,

 

+ job->height,

 

+ kCMVideoCodecType_H264,

 

+ encoderSpecifications,

 

+ NULL,

 

+ NULL,

 

+ &myVTCompressionOutputCallback,

 

+ pv->queue,

 

+ &pv->session);

 

+

 

+ if (err != noErr)

 

+ {

 

+ hb_log("Error creating a VTCompressionSession err=%"PRId64"", (int64_t)err);

 

+ return err;

 

+ }

 

+

 

+ err = VTSessionSetProperty(pv->session, kVTCompressionPropertyKey_AllowFrameReordering, kCFBooleanTrue);

 

+ if (err != noErr)

 

+ hb_log("VTSessionSetProperty: kVTCompressionPropertyKey_AllowFrameReordering failed");

 

+

 

+ const int maxKeyFrameInterval = 10 * 30;

 

+ err = VTSessionSetProperty(pv->session, kVTCompressionPropertyKey_MaxKeyFrameInterval,

 

+ CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &maxKeyFrameInterval));

 

+ if (err != noErr)

 

+ hb_log("VTSessionSetProperty: kVTCompressionPropertyKey_MaxKeyFrameInterval failed");

 

+

 

+ const int maxFrameDelayCount = 24;

 

+ err = VTSessionSetProperty(pv->session, kVTCompressionPropertyKey_MaxFrameDelayCount,

 

+ CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &maxFrameDelayCount));

 

+ if (err != noErr)

 

+ 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));

 

+ if (err != noErr)

 

+ 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));

 

+ if (err != noErr)

 

+ hb_log("VTSessionSetProperty: kVTCompressionPropertyKey_AverageBitRate failed");

 

+ }

 

+

 

+ err = VTSessionSetProperty(pv->session, kVTCompressionPropertyKey_ProfileLevel, kVTProfileLevel_H264_High_5_0);

 

+ if (err != noErr)

 

+ hb_log("VTSessionSetProperty: kVTCompressionPropertyKey_ProfileLevel failed");

 

+

 

+ CFRelease(encoderSpecifications);

 

+

 

+ return err;

 

+}

 

+

 

+void setupMagicCookie(hb_work_object_t * w, hb_job_t * job, hb_work_private_t * pv)

 

+{

 

+ OSStatus err;

 

+ 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,

 

+ job->width,

 

+ job->height,

 

+ kCVPixelFormatType_24RGB,

 

+ rgbBuf,

 

+ job->width * 3,

 

+ &pixelBufferReleaseBytesCallback,

 

+ NULL,

 

+ NULL,

 

+ &pxbuffer);

 

+

 

+ if (kCVReturnSuccess != err)

 

+ hb_log("VTCompressionSession: CVPixelBuffer error");

 

+

 

+ CMTime pts = CMTimeMake(0, 90000);

 

+ err = VTCompressionSessionEncodeFrame(

 

+ pv->session,

 

+ pxbuffer,

 

+ pts,

 

+ kCMTimeInvalid,

 

+ NULL,

 

+ pxbuffer,

 

+ NULL);

 

+ VTCompressionSessionCompleteFrames(pv->session, CMTimeMake(0,90000));

 

+

 

+ CMSampleBufferRef sampleBuffer = (CMSampleBufferRef) CMSimpleQueueDequeue(pv->queue);

 

+

 

+ format = CMSampleBufferGetFormatDescription(sampleBuffer);

 

+ if (!format)

 

+ hb_log("VTCompressionSession: Format Description error");

 

+

 

+ CFDictionaryRef extentions = CMFormatDescriptionGetExtensions(format);

 

+ if (!extentions)

 

+ hb_log("VTCompressionSession: Format Description Extensions error");

 

+

 

+ CFDictionaryRef atoms = CFDictionaryGetValue(extentions, kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms);

 

+ CFDataRef magicCookie = CFDictionaryGetValue(atoms, CFSTR("avcC"));

 

+ if (!magicCookie)

 

+ hb_log("VTCompressionSession: Magic Cookie error");

 

+

 

+ const uint8_t *avcCAtom = CFDataGetBytePtr(magicCookie);

 

+

 

+ SInt64 i;

 

+ int8_t spsCount = (avcCAtom[5] & 0x1f);

 

+ uint8_t ptrPos = 6;

 

+ uint8_t spsPos = 0;

 

+ 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);;

 

+ ptrPos += spsSize;

 

+ spsPos += spsSize;

 

+ }

 

+ w->config->h264.sps_length = spsPos;

 

+

 

+ int8_t ppsCount = avcCAtom[ptrPos++];

 

+ uint8_t ppsPos = 0;

 

+ 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);;

 

+

 

+ ptrPos += ppsSize;

 

+ ppsPos += 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 )

 

+{

 

+ OSStatus err;

 

+ hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );

 

+ w->private_data = pv;

 

+

 

+ pv->job = job;

 

+

 

+ CMSimpleQueueCreate(

 

+ kCFAllocatorDefault,

 

+ 200,

 

+ &pv->queue);

 

+

 

+ setupMagicCookie(w, job, pv);

 

+

 

+ err = initVTSession(w, job, pv);

 

+ if (err != noErr)

 

+ {

 

+ hb_log("Error creating a VTCompressionSession err=%"PRId64"", (int64_t)err);

 

+ *job->die = 1;

 

+ return -1;

 

+ }

 

+

 

+ return 0;

 

+}

 

+

 

+/***********************************************************************

 

+ * Close

 

+ ***********************************************************************

 

+ *

 

+ **********************************************************************/

 

+void encvt_h264Close( hb_work_object_t * w )

 

+{

 

+ hb_work_private_t * pv = w->private_data;

 

+

 

+ VTCompressionSessionInvalidate(pv->session);

 

+ CFRelease(pv->session);

 

+ CFRelease(pv->queue);

 

+

 

+ free( pv );

 

+ w->private_data = NULL;

 

+}

 

+

 

+/***********************************************************************

 

+ * Work

 

+ ***********************************************************************

 

+ *

 

+ **********************************************************************/

 

+

 

+hb_buffer_t* extractData(CMSampleBufferRef sampleBuffer, hb_work_object_t * w)

 

+{

 

+ OSStatus err;

 

+ hb_work_private_t * pv = w->private_data;

 

+ hb_job_t * job = pv->job;

 

+ hb_buffer_t *buf = NULL;

 

+

 

+ CMItemCount samplesNum = CMSampleBufferGetNumSamples(sampleBuffer);

 

+ if (samplesNum > 1)

 

+ hb_log("VTCompressionSession: more than 1 sample in sampleBuffer = %ld", samplesNum);

 

+

 

+ CMBlockBufferRef buffer = CMSampleBufferGetDataBuffer(sampleBuffer);

 

+ if (buffer)

 

+ {

 

+ 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))

 

+ {

 

+ CFBooleanRef b;

 

+ 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);

 

+ if (bv)

 

+ buf->s.frametype = HB_FRAME_P;

 

+ else

 

+ {

 

+ buf->s.frametype = HB_FRAME_B;

 

+ buf->s.flags &= ~HB_FRAME_REF;

 

+ }

 

+ }

 

+ else {

 

+ 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

 

+ chapter start. */

 

+ if( buf->s.frametype == HB_FRAME_IDR && pv->next_chap != 0 && pv->next_chap <= presentationTimeStamp.value )

 

+ {

 

+ pv->next_chap = 0;

 

+ buf->s.new_chap = pv->chap_mark;

 

+ }

 

+ }

 

+

 

+ return buf;

 

+}

 

+

 

+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;

 

+

 

+ OSStatus err;

 

+

 

+ if ( in->size <= 0 )

 

+ {

 

+ // 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 ( buf )

 

+ {

 

+ if ( last_buf == NULL )

 

+ *buf_out = buf;

 

+ else

 

+ last_buf->next = buf;

 

+ last_buf = buf;

 

+ }

 

+ }

 

+

 

+ // Flushed everything - add the eof to the end of the chain.

 

+ if ( last_buf == NULL )

 

+ *buf_out = in;

 

+ else

 

+ last_buf->next = in;

 

+

 

+ *buf_in = NULL;

 

+ return HB_WORK_DONE;

 

+ }

 

+

 

+ // 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(

 

+ kCFAllocatorDefault,

 

+ job->width,

 

+ job->height,

 

+ kCVPixelFormatType_420YpCbCr8Planar,

 

+ in_c->data,

 

+ 0,

 

+ 3,

 

+ planeBaseAddress,

 

+ planeWidth,

 

+ planeHeight,

 

+ planeBytesPerRow,

 

+ &pixelBufferReleasePlanarBytesCallback,

 

+ in_c,

 

+ NULL,

 

+ &pxbuffer);

 

+

 

+ 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 */

 

+ in->s.new_chap = 0;

 

+ }

 

+

 

+ // Send the frame to be encoded

 

+ err = VTCompressionSessionEncodeFrame(

 

+ pv->session,

 

+ pxbuffer,

 

+ CMTimeMake(in->s.start, 90000),

 

+ kCMTimeInvalid,

 

+ frameProperties,

 

+ pxbuffer,

 

+ NULL);

 

+

 

+ if (err)

 

+ hb_log("VTCompressionSession: VTCompressionSessionEncodeFrame error");

 

+

 

+ if (frameProperties)

 

+ CFRelease(frameProperties);

 

+

 

+ // Return a frame if ready

 

+ sampleBuffer = (CMSampleBufferRef) CMSimpleQueueDequeue(pv->queue);

 

+

 

+ if (sampleBuffer)

 

+ {

 

+ buf = extractData(sampleBuffer, w);

 

+ CFRelease(sampleBuffer);

 

+ }

 

+

 

+ *buf_out = buf;

 

+

 

+ return HB_WORK_OK;

 

+}

 

+

3 ?????

libhb/work.c

@@ -1027,6 +1027,9 @@ static void do_job(hb_job_t *job)
 

case HB_VCODEC_X264:

 

w = hb_get_work( WORK_ENCX264 );

 

break;

 

+ case HB_VCODEC_VT_H264:

 

+ w = hb_get_work( WORK_ENCVT_H264 );

 

+ break;

 

case HB_VCODEC_THEORA:

 

w = hb_get_work( WORK_ENCTHEORA );

 

break;

 

18 ?????

macosx/HandBrake.xcodeproj/project.pbxproj

@@ -120,6 +120,12 @@
 

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 */; };

@@ -305,6 +311,9 @@
 

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>"; };

@@ -343,6 +352,9 @@
 

isa = PBXFrameworksBuildPhase;

 

buildActionMask = 2147483647;

 

files = (

 

+ 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 */,

@@ -379,6 +391,9 @@
 

isa = PBXFrameworksBuildPhase;

 

buildActionMask = 2147483647;

 

files = (

 

+ 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 */,

@@ -495,6 +510,9 @@
 

273F203414ADBAC30021BE6D /* Frameworks */ = {

 

isa = PBXGroup;

 

children = (

 

+ A94BC59F1770C0C00055F56B /* CoreVideo.framework */,

 

+ A94BC59C1770C0110055F56B /* CoreMedia.framework */,

 

+ A90156C11770AB9200079F5A /* VideoToolbox.framework */,

 

A9E1467A16BC2ABD00C307BC /* QuartzCore.framework */,

 

273F20C714ADC4FF0021BE6D /* QTKit.framework */,

 

273F202F14ADB9790021BE6D /* AudioToolbox.framework */,

 

2 ?????

test/module.defs

@@ -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

 

TEST.GCC.l += iconv

 

else ifeq ($(BUILD.system),linux)

 

TEST.GCC.l += pthread dl m

 

0 comments
on commit 2c13329

Styling with Markdown is supported

Write
Preview

Attach files by dragging & dropping or selecting them.

You’re not receiving notifications from this thread.

时间: 2024-10-12 22:51:59

HandBrake-QuickSync-Mac (内容:QuickSync encoder via VideoToolbox )的相关文章

IOS Video Tool Box后台解码失败

---恢复内容开始--- 1.VideoToolBox硬件解码H264流的过程中,如果App从前台按Home键进入后台,会立马产生一个-12903的错误  如果这个时候重置解码器,继续解码,会遇到 -12911的错误 ,-12911代表一种数据错误 kVTPropertyNotSupportedErr = -12900, kVTPropertyReadOnlyErr = -12901, kVTParameterErr = -12902, kVTInvalidSessionErr = -12903

linux运维工程师面试题练习

前两天去某游戏公司面试.面试官为运维部女主管.由于笔试写得一塌糊涂,直接被鄙视得不行.女面试官连说话都懒得说.其实很多笔试题都是基础类型,考点也都知道,奈何不好好总结准备.掉坑里了!闲着也是闲着,不如几个题目来做做吧! 题目链接: http://www.yunweipai.com/archives/4443.html 一.Linux操作系统知识 常见的Linux发行版本都有什么?你最擅长哪一个?它的官网网站是什么?说明你擅长哪一块? a,centos redhat ubuntu b.centos

mac安装office2011,提示无法打开文件Normal.dotm,因为内容有错误

最近使用mac上的office,发现一个问题,每次打开office11都会报错,提示“无法打开文件Normal.dotm,因为内容有错误”,于是就在网络上搜索了一下,找到如下一段话, I just found out that my kids were playing on my computer and accidentally renamed my main drive to "]?[". After renaming it something appropriate, it op

linux,Mac下 ls 查看目录(文件夹)内容大小

习惯Terminal没有不知道ls命令的(等同于DOS的dir),经常只是需要查看目录的内容大小,但ls -h显示的只是目录的本身大小,而且很多项内容 ls 在这方面的两个诟病出现了: 小诟1. 显示的信息很全,我们只提取Size和Name两列,分别是第5和9列 但是发现不对,像Edge的话起码有200G,但是为什么显示的是306B,说明ls只是显示目录的本身大小,不显示内容大小 大诟2. 不显示目录的实际大小,要显示目录(文件夹)的内容大小,需要用到du(disk utility的缩写)来显示

MAC系统崩溃,使用命令行复制硬盘内容

MAC系统坏了,又无法重装的时候,只需要按以下操作就可以复制出重要的文件. 1.准备好外接存储设备 准备一个空的且足够大的移动硬盘或U盘 进入恢复模式 1).长按option启动 或者 2).按command+R 效果是一样的,都是将文件载入内存中 启动“磁盘工具”,选择“抹盘”.这一步是将外接存储介质换成苹果系统支持的格式,一般来说使用系统默认的那个格式即可,不用更改. 2.进入目录 cd /Volumes/Macintosh HD/Users/your account name/ 其中 yo

HandBrake Mac/Windows 视频压缩工具.

给大家安利个好用的视频压缩工具. 一.下载安装: 下载地址: HandBrake-Downloads. 或者直接点击: Mac OS X系统下载. Windows系统下载. 根据自己的电脑系统选择相应的软件包下载! 二.使用: 我的电脑系统为Mac OS X, 下载的时候,最新版本为: 1.2.2 由于作者没有配置中文,所有选项/功能都是英文,所以我做了一个简单的翻译注释. 这是主窗口-摘要面板内容. 这是外形尺寸面板内容. 这是过滤器面板内容. 这是视频面板内容. 这是音频面板内容. 最后的

How to encode picture to H264 use AVFoundation on Mac, not use x264(续 :其中提到的用VideoToolBox硬编码,RTMP推流的开源工程 VideoCore project)

来源:https://github.com/jgh-/VideoCore Code Issues 77 Pull requests 4 Wiki Pulse Graphs SSH clone URL You can clone with , , or . An audio and video manipulation pipeline 421 commits 5 branches 43 releases 10 contributors C++ 58.0% Objective-C++ 32.9%

R 读取clipboard内容 (MAC)

在mac上,R读取复制的data.很简单,一行命令 read.table(pipe("pbpaste"))

捕捉SSID名称和MAC地址然后整形输出至文本(如何格式化普通文本内容到Powershell友好的格式:)

$raw = netsh wlan show network mode=bssid $ssids = $raw | Select-String -Pattern 'SSID\b'| Select-String -Pattern '\bBSSID\s[^1]\b' -NotMatch | ForEach-Object { $_.ToString().PadRight(11) + '_' #有些扫描出来的SSID没有名字, 所以我干脆让所有SSOD名称后都加一个下划线, 以确保后续的格式正确 } $