播放YUV
- (void)play {
//
NSTimeInterval interval = 1.0 / _yuv.fps * 1.0;
__weak typeof(self)weakSelf = self;
self.timer = [NSTimer timerWithTimeInterval:interval repeats:true block:^(NSTimer * _Nonnull timer) {
[weakSelf timerAction];
}];
[self.timer fire];
[[NSRunLoop mainRunLoop]addTimer:self.timer forMode:NSRunLoopCommonModes];
}
- 將YUV轉(zhuǎn)換為RGB數(shù)據(jù)
- 用RGB數(shù)據(jù)生成CGimage
- 在view上繪制CGImage
- (void)play {
//
NSTimeInterval interval = 1.0 / _yuv.fps * 1.0;
__weak typeof(self)weakSelf = self;
self.timer = [NSTimer timerWithTimeInterval:interval repeats:true block:^(NSTimer * _Nonnull timer) {
[weakSelf timerAction];
}];
[self.timer fire];
[[NSRunLoop mainRunLoop]addTimer:self.timer forMode:NSRunLoopCommonModes];
}
- (void)setYUV:(YuvParam*)yuv {
_yuv = yuv;
NSInteger format = yuv.pixelFomat;
self.file = [NSFileHandle fileHandleForReadingAtPath: _yuv.filename];
// 一幀圖片的大小
imageSize = av_image_get_buffer_size((AVPixelFormat)_yuv.pixelFomat, _yuv.width, _yuv.height, 1);
// 當(dāng)前控件的大小
CGFloat width = self.bounds.size.width;
CGFloat height = self.bounds.size.height;
// 計算Rect
CGFloat dx = 0;
CGFloat dy = 0;
CGFloat dw = _yuv.width;
CGFloat dh = _yuv.height;
// 計算目標(biāo)尺寸
if (dw > width || dh > height) {
if (dw * height > width * dh) { // 視頻的寬高比 > 播放器的寬高比
dh = width * dh / dw;
dw = width;
} else {
dw = height * dw / dh;
dh = height;
}
}
dx = (width - dw) * 0.5;
dy = (height - dh) * 0.5;
playerRect = CGRectMake(dx, dy, dw, dh);
}
- (CGImageRef)generateImage:(const RawVideoFrame &)output {
int width = output.width;
int height = output.height;
size_t bufferLength = width * height * 3;
char * buffer = output.pixels;
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer, bufferLength, NULL);
size_t bitsPerComponent = 8;
size_t bitsPerPixel = 24;
size_t bytesPerRow = 3 * width;
CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
if(colorSpaceRef == NULL) {
CGDataProviderRelease(provider);
}
CGBitmapInfo bitmapInfo = kCGImageAlphaNone;
CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
CGImageRef iref = CGImageCreate(width,
height,
bitsPerComponent,
bitsPerPixel,
bytesPerRow,
colorSpaceRef,
bitmapInfo,
provider, // data provider
NULL, // decode
NO, // should interpolate
renderingIntent);
return iref;
}
- (void)timerAction {
NSData *imageData = [self.file readDataOfLength:imageSize];
if (imageData.length > 0) {
RawVideoFrame input = {
(char*)imageData.bytes,
static_cast<int>(_yuv.width),
static_cast<int>(_yuv.height),
(AVPixelFormat)_yuv.pixelFomat,
};
RawVideoFrame output = {
nullptr,
static_cast<int>(_yuv.width),
static_cast<int>(_yuv.height),
AV_PIX_FMT_RGB24
};
[FFMpegs convertRawVideo:&input output:&output];
CGImageRef iref = [self generateImage:output];
self.playLayer.contents = (__bridge id)iref;
self.playLayer.frame = playerRect;
} else {
[self.timer invalidate];
self.timer = nil;
}
}
視頻幀格式轉(zhuǎn)換
- 創(chuàng)建轉(zhuǎn)換上下文
- 設(shè)置輸入輸出緩沖區(qū)
- 計算輸出輸出幀的大小
- 開始轉(zhuǎn)換
- 獲取轉(zhuǎn)換后的數(shù)據(jù)
+ (void)convertRawVideo:(RawVideoFrame*)input
output:(RawVideoFrame*)output {
// 上下文
SwsContext *ctx = nullptr;
// 輸入缩挑,輸出緩沖區(qū)(指向每一個平面的數(shù)據(jù))(Y U V apha)
uint8_t *inData[4], *outData[4];
// 每一個平面的一行大小
int inStrides[4], ouStrides[4];
// 每一幀圖片的大小
int inFrameSize, outFrameSize;
int ret = 0;
// 創(chuàng)建上下文
ctx = sws_getContext(input->width, input->height, input->format,
output->width, output->height, output->format,
SWS_BILINEAR, nullptr, nullptr, nullptr);
if(!ctx) {
NSLog(@"sws_getContext error");
goto end;
}
// 輸入緩沖區(qū)
ret = av_image_alloc(inData, inStrides,
input->width,
input->height,
input->format, 1);
END(av_image_alloc);
// 輸出緩沖區(qū)
ret = av_image_alloc(outData, ouStrides,
output->width,
output->height,
output->format, 1);
END(av_image_alloc);
// 計算每一幀的大小
inFrameSize = av_image_get_buffer_size(input->format, input->width, input->height, 1);
outFrameSize = av_image_get_buffer_size(output->format, output->width, output->height, 1);
// 拷貝輸入數(shù)據(jù)
memcpy(inData[0], input->pixels, inFrameSize);
// 轉(zhuǎn)換
sws_scale(ctx,
inData, inStrides, 0, input->height,
outData, ouStrides);
// 寫到輸出文件去
output->frameSize = outFrameSize;
output->pixels = (char*)malloc(outFrameSize);
memcpy(output->pixels, outData[0], outFrameSize);
end:
NSLog(@"end");
av_freep(&inData[0]);
av_freep(&outData[0]);
sws_freeContext(ctx);
}