我正在尝试将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);
}