예제 #1
0
int qEncodeAPI(QEncoder* encoder, char* bytes, int byteSize)
{
    OSErr err;
    CVPixelBufferPoolRef pixelBufferPool;
    CVPixelBufferRef pixelBuffer;
    unsigned char* baseAddress;
    size_t bufferSize;

    // Grab a pixel buffer from the pool (ICMCompressionSessionEncodeFrame() needs the input
    // data to be passed in as a CVPixelBufferRef).
    pixelBufferPool = ICMCompressionSessionGetPixelBufferPool(encoder->session);
    err = CVPixelBufferPoolCreatePixelBuffer(kCFAllocatorDefault, pixelBufferPool, &pixelBuffer);
    if (err != noErr) {
        fprintf(QSTDERR, "\nqEncodeQT(): could not obtain a pixel buffer from pool");
        fprintf(QSTDERR, "\n\tQUICKTIME ERROR CODE: %d", err);
        return -5;
    }

    // Lock the pixel-buffer so that we can copy our data into it for encoding
    // XXXX: would be nice to avoid this copy.
    err = CVPixelBufferLockBaseAddress(pixelBuffer, 0);
    if (err != noErr) {
        fprintf(QSTDERR, "\nqEncodeQT(): could not lock the pixel buffer");
        fprintf(QSTDERR, "\n\tQUICKTIME ERROR CODE: %d", err);
        CVPixelBufferRelease(pixelBuffer);
        return -5;
    }
    baseAddress = CVPixelBufferGetBaseAddress(pixelBuffer);
//	bufferSize = CVPixelBufferGetWidth(pixelBuffer) * CVPixelBufferGetHeight(pixelBuffer) * 4;
    bufferSize = CVPixelBufferGetBytesPerRow(pixelBuffer) * CVPixelBufferGetHeight(pixelBuffer);

    // XXXX: for now, just for debugging.  For production, we should notice if this happens and deal with it "appropriately".
    if (byteSize != bufferSize) {
        fprintf(QSTDERR, "\nqEncodeQT(): input data size (%d) does not match pixel-buffer data size (%d)", byteSize, bufferSize);
    }

    // Copy the data and unlock the buffer
    memcpy(baseAddress, bytes, bufferSize);
    CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);

    // Encode the frame (now in pixel-buffer form).
    err = ICMCompressionSessionEncodeFrame(	encoder->session,
                                            pixelBuffer,
                                            0, 0, 0, // we're not specifying a frame time
                                            NULL,
                                            NULL,
                                            NULL);
    if (err != noErr) {
        fprintf(QSTDERR, "\nqEncodeQT(): could not encode the frame");
        fprintf(QSTDERR, "\n\tQUICKTIME ERROR CODE: %d", err);
        CVPixelBufferRelease(pixelBuffer);
        return -5;
    }

    CVPixelBufferRelease(pixelBuffer);
    return 0;
}
예제 #2
0
bool UBQuickTimeFile::createCompressionSession()
{
    CodecType codecType = kH264CodecType;

    CFStringRef keys[] = {kCVPixelBufferPixelFormatTypeKey, kCVPixelBufferWidthKey, kCVPixelBufferHeightKey};

    int width = mFrameSize.width();
    int height = mFrameSize.height();
    int pixelFormat = k32BGRAPixelFormat;

    CFTypeRef values[] =
    {
        (CFTypeRef)CFNumberCreate(0, kCFNumberIntType, (void*)&pixelFormat),
        (CFTypeRef)CFNumberCreate(0, kCFNumberIntType, (void*)&width),
        (CFTypeRef)CFNumberCreate(0, kCFNumberIntType, (void*)&height)
    };

    CFDictionaryRef pixelBufferAttributes = CFDictionaryCreate(kCFAllocatorDefault
            , (const void **)keys, (const void **)values, 3, 0, 0);

    if(!pixelBufferAttributes)
    {
        setLastErrorMessage("Could not create CV buffer pool pixel buffer attributes");
        return false;
    }

    OSStatus err = noErr;
    ICMEncodedFrameOutputRecord encodedFrameOutputRecord = {0};
    ICMCompressionSessionOptionsRef sessionOptions = 0;

    err = ICMCompressionSessionOptionsCreate(0, &sessionOptions);
    if(err)
    {
        setLastErrorMessage(QString("ICMCompressionSessionOptionsCreate() failed %1").arg(err));
        goto bail;
    }

    // We must set this flag to enable P or B frames.
    err = ICMCompressionSessionOptionsSetAllowTemporalCompression(sessionOptions, true);
    if(err)
    {
        setLastErrorMessage(QString("ICMCompressionSessionOptionsSetAllowTemporalCompression() failed %1").arg(err));
        goto bail;
    }

    // We must set this flag to enable B frames.
    err = ICMCompressionSessionOptionsSetAllowFrameReordering(sessionOptions, true);
    if(err)
    {
        setLastErrorMessage(QString("ICMCompressionSessionOptionsSetAllowFrameReordering() failed %1").arg(err));
        goto bail;
    }

    // Set the maximum key frame interval, also known as the key frame rate.
    err = ICMCompressionSessionOptionsSetMaxKeyFrameInterval(sessionOptions, mFramesPerSecond);
    if(err)
    {
        setLastErrorMessage(QString("ICMCompressionSessionOptionsSetMaxKeyFrameInterval() failed %1").arg(err));
        goto bail;
    }

    // This allows the compressor more flexibility (ie, dropping and coalescing frames).
    err = ICMCompressionSessionOptionsSetAllowFrameTimeChanges(sessionOptions, true);
    if(err)
    {
        setLastErrorMessage(QString("ICMCompressionSessionOptionsSetAllowFrameTimeChanges() failed %1").arg(err));
        goto bail;
    }

    // Set the average quality.
    err = ICMCompressionSessionOptionsSetProperty(sessionOptions,
                                                      kQTPropertyClass_ICMCompressionSessionOptions,
                                                      kICMCompressionSessionOptionsPropertyID_Quality,
                                                      sizeof(mSpatialQuality),
                                                      &mSpatialQuality);
    if(err)
    {
        setLastErrorMessage(QString("ICMCompressionSessionOptionsSetProperty(Quality) failed %1").arg(err));
        goto bail;
    }

    //qDebug() << "available quality" << mSpatialQuality;

    encodedFrameOutputRecord.encodedFrameOutputCallback = addEncodedFrameToMovie;
    encodedFrameOutputRecord.encodedFrameOutputRefCon = this;
    encodedFrameOutputRecord.frameDataAllocator = 0;

    err = ICMCompressionSessionCreate(0, mFrameSize.width(), mFrameSize.height(), codecType, mTimeScale,
                                                                      sessionOptions, pixelBufferAttributes, &encodedFrameOutputRecord, &mVideoCompressionSession);
    if(err)
    {
        setLastErrorMessage(QString("ICMCompressionSessionCreate() failed %1").arg(err));
        goto bail;
    }

    mCVPixelBufferPool = ICMCompressionSessionGetPixelBufferPool(mVideoCompressionSession);

    if(!mCVPixelBufferPool)
    {
        setLastErrorMessage("ICMCompressionSessionGetPixelBufferPool() failed.");
        err = !noErr;
        goto bail;
    }

    if(mRecordAudio)
    {
        mWaveRecorder = new UBAudioQueueRecorder();

        if(mWaveRecorder->init(mAudioRecordingDeviceName))
        {
            connect(mWaveRecorder, SIGNAL(newWaveBuffer(void*, long, int , const AudioStreamPacketDescription*))
                                    , this, SLOT(appendAudioBuffer(void*, long, int, const AudioStreamPacketDescription*)));

            connect(mWaveRecorder, SIGNAL(audioLevelChanged(quint8)), this, SIGNAL(audioLevelChanged(quint8)));
        }
        else
        {