FFmpeg如何使用avcodec_send_frame()和avcodec_receive_packet()新API

时间:2018-08-07 11:16:09

标签: ffmpeg

我正在尝试将CMSampleBufferRef转换为AVPacket并将其写入文件中,但是不建议使用avcodec_encode_video2()方法,请调用新的API avcodec_receive_packet(),该方法始终返回AVERROR(EAGAIN),如何使用此API。

这是我的代码:

- (void)encodeFrameWithSampleBufferRef:(CMSampleBufferRef)sampleBuffer {
    CVImageBufferRef imageBufferRef = CMSampleBufferGetImageBuffer(sampleBuffer);

    if (CVPixelBufferLockBaseAddress(imageBufferRef, 0) == kCVReturnSuccess) {

        UInt8 *bufferYPtr = (UInt8 *)CVPixelBufferGetBaseAddressOfPlane(imageBufferRef, 0);
        UInt8 *bufferUVPtr = (UInt8 *)CVPixelBufferGetBaseAddressOfPlane(imageBufferRef, 1);

        size_t realWidth = CVPixelBufferGetWidth(imageBufferRef);
        size_t realHeight = CVPixelBufferGetHeight(imageBufferRef);
        size_t yBytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(imageBufferRef, 0);
        size_t uvBytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(imageBufferRef, 1);

        UInt8 *dateYUV420 = (UInt8 *)malloc(realWidth * realHeight * 3 / 2);
        UInt8 *pU = dateYUV420 + realWidth * realHeight;
        UInt8 *pV = pU + realWidth * realHeight * 1 / 4;

        for (int i = 0; i < realHeight; i++) {
            memcpy(dateYUV420 + i * realWidth, bufferYPtr + i * yBytesPerRow, realWidth);
        }
        for (int i = 0; i < realHeight / 2; i++) {
            for (int j = 0; j < realWidth / 2; j++) {
                *(pU++) = bufferUVPtr[j<<1];
                *(pV++) = bufferUVPtr[((j<<1) + 1)];
            }
            bufferUVPtr += uvBytesPerRow;
        }

        _frame -> data[0] = dateYUV420;
        _frame -> data[1] = dateYUV420 + realWidth * realHeight;
        _frame -> data[2] = dateYUV420 + realWidth * realHeight + realWidth * realHeight * 1 / 4;
        _frame -> width = (CGFloat)realWidth;
        _frame -> height = (CGFloat)realHeight;
        _frame -> format = AV_PIX_FMT_YUV420P;

        // encode
        int ret = avcodec_send_frame(_codecContext, _frame);
        if (ret < 0) {
            fprintf(stderr, "Error sending a frame for encoding\n");
            exit(1);
        }
        while (ret >= 0) {
            ret = avcodec_receive_packet(_codecContext, &_packet);
            if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
                return;
            } else if (ret < 0) {
                fprintf(stderr, "Error during encoding\n");
                exit(1);
            }
            av_write_frame(_formatContext, &_packet);
            av_packet_unref(&_packet);
        }

        free(dateYUV420);
    }

    CVPixelBufferUnlockBaseAddress(imageBufferRef, 0);
}

0 个答案:

没有答案