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


    来源: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.
    1. +10 −8 
     
     
    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

     
    @depthlove
     

    Attach files by dragging & dropping or selecting them.

     
     
     
     

    You’re not receiving notifications from this thread.

  • 相关阅读:
    031.NET5_ActionFilter的自定义和执行特点
    030.NET5_Autofac单抽象多实现属性注入
    029.NET5_Autofac单抽象多实现构造函数注入
    028.NET5_Autofac通过类支持AOP
    vue 设置回车input提交
    vscode设置全局自动换行
    vscode 插件大全
    SQL Server 2019基础配置
    SQL Server 2019 安装教程
    phpstudy(php环境)设置内网访问
  • 原文地址:https://www.cnblogs.com/sunminmin/p/4976409.html
Copyright © 2020-2023  润新知