• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

FFmpeg 播放 YUV

武飞扬头像
Hanyang Li
帮助1

1. 创建分类

  1.1 创建 View 分类

    1) 创建头文件,UIView Category.h

  1.  
    #import <UIKit/UIKit.h>
  2.  
     
  3.  
    NS_ASSUME_NONNULL_BEGIN
  4.  
     
  5.  
    @interface UIView (Category)
  6.  
    @property (nonatomic, assign) CGFloat x;
  7.  
    @property (nonatomic, assign) CGFloat y;
  8.  
    @property (nonatomic, assign) CGFloat width;
  9.  
    @property (nonatomic, assign) CGFloat height;
  10.  
    @property (nonatomic, assign) CGFloat centerX;
  11.  
    @property (nonatomic, assign) CGFloat centerY;
  12.  
    @property (nonatomic, assign) CGSize size;
  13.  
    @property (nonatomic, assign) CGPoint origin;
  14.  
    @end
  15.  
     
  16.  
    NS_ASSUME_NONNULL_END
学新通

    2) 实现头文件,UIView Category.m

  1.  
    #import "UIView Category.h"
  2.  
     
  3.  
    @implementation UIView (Category)
  4.  
     
  5.  
    - (void)setX:(CGFloat)x
  6.  
    {
  7.  
    CGRect frame = self.frame;
  8.  
    frame.origin.x = x;
  9.  
    self.frame = frame;
  10.  
    }
  11.  
     
  12.  
    - (void)setY:(CGFloat)y
  13.  
    {
  14.  
    CGRect frame = self.frame;
  15.  
    frame.origin.y = y;
  16.  
    self.frame = frame;
  17.  
    }
  18.  
     
  19.  
    - (CGFloat)x
  20.  
    {
  21.  
    return self.frame.origin.x;
  22.  
    }
  23.  
     
  24.  
    - (CGFloat)y
  25.  
    {
  26.  
    return self.frame.origin.y;
  27.  
    }
  28.  
     
  29.  
    - (void)setCenterX:(CGFloat)centerX
  30.  
    {
  31.  
    CGPoint center = self.center;
  32.  
    center.x = centerX;
  33.  
    self.center = center;
  34.  
    }
  35.  
     
  36.  
    - (CGFloat)centerX
  37.  
    {
  38.  
    return self.center.x;
  39.  
    }
  40.  
     
  41.  
    - (void)setCenterY:(CGFloat)centerY
  42.  
    {
  43.  
    CGPoint center = self.center;
  44.  
    center.y = centerY;
  45.  
    self.center = center;
  46.  
    }
  47.  
     
  48.  
    - (CGFloat)centerY
  49.  
    {
  50.  
    return self.center.y;
  51.  
    }
  52.  
     
  53.  
    - (void)setWidth:(CGFloat)width
  54.  
    {
  55.  
    CGRect frame = self.frame;
  56.  
    frame.size.width = width;
  57.  
    self.frame = frame;
  58.  
    }
  59.  
     
  60.  
    - (void)setHeight:(CGFloat)height
  61.  
    {
  62.  
    CGRect frame = self.frame;
  63.  
    frame.size.height = height;
  64.  
    self.frame = frame;
  65.  
    }
  66.  
     
  67.  
    - (CGFloat)height
  68.  
    {
  69.  
    return self.frame.size.height;
  70.  
    }
  71.  
     
  72.  
    - (CGFloat)width
  73.  
    {
  74.  
    return self.frame.size.width;
  75.  
    }
  76.  
     
  77.  
    - (void)setSize:(CGSize)size
  78.  
    {
  79.  
    CGRect frame = self.frame;
  80.  
    frame.size = size;
  81.  
    self.frame = frame;
  82.  
    }
  83.  
     
  84.  
    - (CGSize)size
  85.  
    {
  86.  
    return self.frame.size;
  87.  
    }
  88.  
     
  89.  
    - (void)setOrigin:(CGPoint)origin
  90.  
    {
  91.  
    CGRect frame = self.frame;
  92.  
    frame.origin = origin;
  93.  
    self.frame = frame;
  94.  
    }
  95.  
     
  96.  
    - (CGPoint)origin
  97.  
    {
  98.  
    return self.frame.origin;
  99.  
    }
  100.  
     
  101.  
    @end
学新通

  1.2 创建 Image 分类

    1) 创建头文件,UIImage Category.h

  1.  
    #import <UIKit/UIKit.h>
  2.  
     
  3.  
    NS_ASSUME_NONNULL_BEGIN
  4.  
     
  5.  
    @interface UIImage (Category)
  6.  
     
  7.  
    (instancetype)withColor:(UIColor *)color;
  8.  
     
  9.  
    (instancetype)imageFromRGB:(const UInt8 *)data linesize:(int)linesize width:(int)width height:(int)height;
  10.  
     
  11.  
    (instancetype)withScreenShotForView:(UIView *)view;
  12.  
     
  13.  
    (instancetype)withPhotoForView:(UIView *)view;
  14.  
     
  15.  
    @end
  16.  
     
  17.  
    NS_ASSUME_NONNULL_END
学新通

    2) 实现头文件,UIImage Category.m

  1.  
    #import "UIImage Category.h"
  2.  
    #import "UIView Category.h"
  3.  
    #import <AudioToolbox/AudioToolbox.h>
  4.  
     
  5.  
    @implementation UIImage (Category)
  6.  
     
  7.  
    /// 颜色转图片
  8.  
    /// - Parameter color: 色值
  9.  
    (instancetype)withColor:(UIColor *)color{
  10.  
    CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
  11.  
    UIGraphicsBeginImageContext(rect.size);
  12.  
    CGContextRef context = UIGraphicsGetCurrentContext();
  13.  
    CGContextSetFillColorWithColor(context, [color CGColor]);
  14.  
    CGContextFillRect(context, rect);
  15.  
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
  16.  
    UIGraphicsEndImageContext();
  17.  
    return image;
  18.  
    }
  19.  
     
  20.  
    /// RGB 数据转换Image
  21.  
    /// - Parameters:
  22.  
    /// - buffer: RGB 数据
  23.  
    /// - linesize: 行大小
  24.  
    /// - width: 宽
  25.  
    /// - height: 高
  26.  
    (instancetype)imageFromRGB:(const UInt8 *)buffer linesize:(int)linesize width:(int)width height:(int)height{
  27.  
    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
  28.  
    CFDataRef dataRef = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, buffer, linesize * height,kCFAllocatorNull);
  29.  
    CGDataProviderRef provider = CGDataProviderCreateWithCFData(dataRef);
  30.  
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
  31.  
    CGImageRef cgImage = CGImageCreate(width,
  32.  
    height,
  33.  
    8,
  34.  
    24,
  35.  
    linesize,
  36.  
    colorSpace,
  37.  
    bitmapInfo,
  38.  
    provider,
  39.  
    NULL,
  40.  
    NO,
  41.  
    kCGRenderingIntentDefault);
  42.  
    CGColorSpaceRelease(colorSpace);
  43.  
    UIImage *image = [UIImage imageWithCGImage:cgImage];
  44.  
    CGImageRelease(cgImage);
  45.  
    CGDataProviderRelease(provider);
  46.  
    CFRelease(dataRef);
  47.  
    return image;
  48.  
    }
  49.  
     
  50.  
    /// View转图片 截取view生成图片
  51.  
    /// - Parameter view: 视图转图片
  52.  
    (instancetype)withScreenShotForView:(UIView *)view{
  53.  
    UIImage *image = nil;
  54.  
    CGSize size = CGSizeMake(view.width, view.height);
  55.  
    UIGraphicsBeginImageContextWithOptions(size, YES, [UIScreen mainScreen].scale);
  56.  
    [view.layer renderInContext:UIGraphicsGetCurrentContext()];
  57.  
    image = UIGraphicsGetImageFromCurrentImageContext();
  58.  
    UIGraphicsEndImageContext();
  59.  
    /*CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], rect);
  60.  
    image = [UIImage imageWithCGImage:imageRef];
  61.  
    CGImageRelease(imageRef);*/
  62.  
    return image;
  63.  
    }
  64.  
     
  65.  
    /// 系统图片转图片加提示音
  66.  
    /// - Parameter view: 视图转图片
  67.  
    (instancetype)withPhotoForView:(UIView *)view{
  68.  
    UIGraphicsBeginImageContextWithOptions(view.bounds.size, NO, 0);
  69.  
    //UIGraphicsBeginImageContext(view.bounds.size);
  70.  
    [view.layer renderInContext:UIGraphicsGetCurrentContext()];
  71.  
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
  72.  
    UIGraphicsEndImageContext();
  73.  
    // UIImageWriteToSavedPhotosAlbum(img, self, nil, nil);
  74.  
    AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
  75.  
    SystemSoundID soundId;
  76.  
    NSString *path = @"/System/Library/Audio/UISounds/photoShutter.caf";
  77.  
    //[[NSBundle mainBundle]pathForResource:music ofType:@"mp3"];
  78.  
    AudioServicesCreateSystemSoundID((__bridge CFURLRef)[NSURL fileURLWithPath:path], &soundId);
  79.  
    AudioServicesPlaySystemSound(soundId);
  80.  
    return image;
  81.  
    }
  82.  
     
  83.  
    @end
学新通

2. 封装播放 YUV 管理器

  2.1 创建头文件,YUVPlayer.h

  1.  
    #import <Foundation/Foundation.h>
  2.  
    #import <UIKit/UIKit.h>
  3.  
     
  4.  
     
  5.  
    NS_ASSUME_NONNULL_BEGIN
  6.  
     
  7.  
    /// 定义回调 Delegate
  8.  
    @protocol YUVPlayerDelegate <NSObject>
  9.  
     
  10.  
    @optional
  11.  
    -(void)showImage:(UIImage *) image;
  12.  
    @end
  13.  
     
  14.  
     
  15.  
    @interface YUVPlayer : NSObject
  16.  
     
  17.  
    @property(nonatomic, assign)id<YUVPlayerDelegate> delegate;
  18.  
     
  19.  
    - (int)init:(int) width height:(int) height;
  20.  
     
  21.  
    - (void)cacheData:(uint8_t *)data withSize:(int) size;
  22.  
     
  23.  
    @end
  24.  
     
  25.  
    NS_ASSUME_NONNULL_END
学新通

  2.2 实现头文件,YUVPlayer.m

  1.  
    #import "YUVPlayer.h"
  2.  
    #import "avformat.h"
  3.  
    #import "imgutils.h"
  4.  
    #import "swscale.h"
  5.  
    #import "UIImage Category.h"
  6.  
     
  7.  
    @interface YUVPlayer(){
  8.  
    AVFrame *frame_yuv;
  9.  
    AVFrame *frame_rgb;
  10.  
    struct SwsContext *sws_ctx;
  11.  
    uint8_t *buffer_src;
  12.  
    int buffer_size;
  13.  
    int data_remain_size;
  14.  
    int write_remain_size;
  15.  
    }
  16.  
    @end
  17.  
     
  18.  
     
  19.  
    @implementation YUVPlayer
  20.  
     
  21.  
     
  22.  
    /// 初始化
  23.  
    /// - Parameters:
  24.  
    /// - width: 宽
  25.  
    /// - height: 高
  26.  
    - (int)init:(int)width height:(int)height{
  27.  
    frame_yuv = NULL;
  28.  
    frame_rgb = NULL;
  29.  
    sws_ctx = NULL;
  30.  
    buffer_src = NULL;
  31.  
    buffer_size = 0;
  32.  
    data_remain_size = 0;
  33.  
    write_remain_size = 0;
  34.  
     
  35.  
    // 创建需要编码的一帧
  36.  
    frame_yuv = av_frame_alloc();
  37.  
    if(!frame_yuv){
  38.  
    fprintf(stderr, "av_frame_alloc function frame_yuv failed. \n");
  39.  
    return -1;
  40.  
    }
  41.  
    // 设置原始帧 YUV 宽高 848 480
  42.  
    frame_yuv->width = width;
  43.  
    frame_yuv->height = height;
  44.  
    // 设置 YUV 格式
  45.  
    frame_yuv->format = AV_PIX_FMT_YUV420P;
  46.  
    //ret = av_frame_get_buffer(frame_src, 1);//按 32 位对齐
  47.  
     
  48.  
    // yuv 数据 根据需要的解码类型,获取需要的 buffer,结束 free 掉数据
  49.  
    buffer_size = av_image_get_buffer_size(frame_yuv->format, frame_yuv->width, frame_yuv->height, 1);
  50.  
    buffer_src = av_malloc(buffer_size);//YUV420P: 610560
  51.  
     
  52.  
     
  53.  
    // 根据指定的图像参数和提供的数组,设置数据指针和行数,数据填充到 frame_yuv 里面
  54.  
    //av_image_fill_arrays(frame_yuv->data, frame_yuv->linesize, outBuffer, frame_yuv->format, codec_ctx->width, codec_ctx->height, 1);//32
  55.  
    //RGB24: 1221120
  56.  
    // 初始化转换帧
  57.  
    frame_rgb = av_frame_alloc();
  58.  
    if(!frame_rgb){
  59.  
    fprintf(stderr, "av_frame_alloc function frame_rgb failed. \n");
  60.  
    return -1;
  61.  
    }
  62.  
    // 设置转换 RGB 帧的宽高
  63.  
    frame_rgb->width = width;
  64.  
    frame_rgb->height = height;
  65.  
    // 设置 RGB 格式
  66.  
    frame_rgb->format = AV_PIX_FMT_RGB24;
  67.  
    // 赋值填充帧数据
  68.  
    av_image_alloc(frame_rgb->data, frame_rgb->linesize, frame_rgb->width, frame_rgb->height, frame_rgb->format, 1);
  69.  
    // 获取转换帧内容
  70.  
    sws_ctx = sws_getContext(frame_yuv->width, frame_yuv->height, frame_yuv->format, frame_rgb->width, frame_rgb->height,
  71.  
    frame_rgb->format, SWS_FAST_BILINEAR, NULL, NULL, NULL);
  72.  
    if(!sws_ctx){
  73.  
    fprintf(stderr, "sws_getContext function failed. \n");
  74.  
    return -1;
  75.  
    }
  76.  
    printf("YUVToRGBShow init success.\n");
  77.  
    return 0;
  78.  
    }
  79.  
     
  80.  
    /// 缓存 YUV 数据
  81.  
    /// - Parameters:
  82.  
    /// - data: YUV 数据
  83.  
    /// - size: YUV 数据大小
  84.  
    - (void)cacheData:(uint8_t *)data withSize:(int)size{
  85.  
    // 传递过来的数据当前大小
  86.  
    int current_size = (int)size;
  87.  
    // 每次只能编码 YUV 数据的大小
  88.  
    int yuv_length = buffer_size;
  89.  
    // 累计传递过来的数据,每次用了多少数据
  90.  
    write_remain_size = 0;
  91.  
    while (current_size > 0) {
  92.  
     
  93.  
    if(current_size >= yuv_length){
  94.  
    // 当前剩余的数据大于或者等于解码设定的数据
  95.  
    // 当循环进行编码时,传过来的余留数据大于或者等于 YUV 设定长度的时候,余留数据为 0
  96.  
    if(data_remain_size >= yuv_length){
  97.  
    data_remain_size = 0;
  98.  
    }
  99.  
    // 需要编码的数据长度
  100.  
    int copy_length = yuv_length - data_remain_size;
  101.  
    // 取前面等于 YUV 数据的大小
  102.  
    memcpy(buffer_src data_remain_size, data write_remain_size, copy_length);
  103.  
    // 获取完整一帧数据,进行编码
  104.  
    [self yuvToImage:buffer_src withSize: yuv_length];
  105.  
    // 当前的数据的大小
  106.  
    current_size -= copy_length;
  107.  
    // 写了多少数据
  108.  
    write_remain_size = copy_length;
  109.  
    // 余留多少数据
  110.  
    data_remain_size = current_size;
  111.  
     
  112.  
    }else if(size >= yuv_length){
  113.  
    // 接收的数据大于或者等于解码设定的数据时,余留的数据进行缓存
  114.  
    // 如果余留的数据小于编码的数据,缓存数据
  115.  
    memcpy(buffer_src, data write_remain_size, data_remain_size);
  116.  
    // 当前的数据为 0 current_size == data_remain_size
  117.  
    current_size -= data_remain_size;
  118.  
     
  119.  
    }else{
  120.  
    // 传过来的数据小于 YUV 设定长度的时候,进行缓存,大于或者等于时候,进行编码和缓存
  121.  
    // 当前数据的总长度
  122.  
    int sum_length = data_remain_size current_size;
  123.  
    // 总长度大于或者等于 YUV 设置长度的时候
  124.  
    if(sum_length >= yuv_length){
  125.  
    // 需要拷贝的长度
  126.  
    int copy_length = yuv_length - data_remain_size;
  127.  
    // 拷贝需要编码的数据
  128.  
    memcpy(buffer_src data_remain_size , data, copy_length);
  129.  
    // 获取完整一帧数据,进行编码
  130.  
    [self yuvToImage: buffer_src withSize: yuv_length];
  131.  
    // 当前数据剩余的大小
  132.  
    current_size -= copy_length;
  133.  
    // 写了多少数据
  134.  
    write_remain_size = copy_length;
  135.  
    // 余留数据用完,置为0
  136.  
    data_remain_size = 0;
  137.  
    }else{
  138.  
    // 当传过来的数据小于设定编码数据大小的时候,缓存传过来的数据
  139.  
    memcpy(buffer_src data_remain_size, data write_remain_size, current_size);
  140.  
    // 每次缓存余留数据大小的累加
  141.  
    data_remain_size = current_size;
  142.  
    // 当前数据已经缓存时,当前数据大小置为0
  143.  
    current_size = 0;
  144.  
    }
  145.  
    }
  146.  
    }
  147.  
    }
  148.  
     
  149.  
    /// YUV 转换 RGB ,RGB 转换 Image
  150.  
    /// - Parameters:
  151.  
    /// - data: YUV 数据
  152.  
    /// - size: YUV 数据大小
  153.  
    - (void)yuvToImage:(const uint8_t *)data withSize:(int)size{
  154.  
    // 内存自动释放池
  155.  
    @autoreleasepool {
  156.  
    // 填充 frame_yuv
  157.  
    int ret = av_image_fill_arrays(frame_yuv->data, frame_yuv->linesize, data, frame_yuv->format, frame_yuv->width, frame_yuv->height, 1);//按几位对齐
  158.  
    if(ret == 0){
  159.  
    fprintf(stderr, "av_image_fill_arrays function failed. \n");
  160.  
    return;
  161.  
    }
  162.  
    // 转换 RGB
  163.  
    ret = sws_scale(sws_ctx, (const uint8_t **)frame_yuv->data, frame_yuv->linesize, 0, frame_rgb->height, frame_rgb->data, frame_rgb->linesize);
  164.  
    if(ret == 0){
  165.  
    fprintf(stderr, "sws_scale function failed. \n");
  166.  
    return;
  167.  
    }
  168.  
    // 根据 RGB 数据生成 Image
  169.  
    UIImage *image = [UIImage imageFromRGB:frame_rgb->data[0] linesize:frame_rgb->linesize[0] width:frame_rgb->width height:frame_rgb->height];
  170.  
    if(!image){
  171.  
    fprintf(stderr, "RGB convert image failed. \n");
  172.  
    return;
  173.  
    }
  174.  
    // 返回 Image
  175.  
    if([self.delegate respondsToSelector:@selector(showImage:)]){
  176.  
    // 返回 Image
  177.  
    [self.delegate showImage:image];
  178.  
    // 睡眠 30 毫秒
  179.  
    usleep(30 * 1000);
  180.  
    }
  181.  
    }
  182.  
    }
  183.  
     
  184.  
    /// 释放播放器数据
  185.  
    - (void) close{
  186.  
    if(sws_ctx){
  187.  
    sws_freeContext(sws_ctx);
  188.  
    sws_ctx = NULL;
  189.  
    }
  190.  
    if(frame_yuv){
  191.  
    av_frame_free(&frame_yuv);
  192.  
    frame_yuv = NULL;
  193.  
    }
  194.  
    if(frame_rgb){
  195.  
    av_frame_free(&frame_rgb);
  196.  
    frame_rgb = NULL;
  197.  
    }
  198.  
    if(buffer_src){
  199.  
    av_free(buffer_src);
  200.  
    buffer_src = NULL;
  201.  
    }
  202.  
    printf("YUVToRGBShow close.\n");
  203.  
    }
  204.  
     
  205.  
    /// 释放数据
  206.  
    - (void)dealloc{
  207.  
    [self close];
  208.  
    }
  209.  
     
  210.  
    @end
学新通

3. 测试函数及效果图

  3.1 测试函数 onClickYUVPlayer,ViewController.m

  1.  
    #import "ViewController.h"
  2.  
    #import "UIView Category.h"
  3.  
    #import "PathTool.h"
  4.  
    #import "FileTool.h"
  5.  
    #import "MediaFileSeparation.h"
  6.  
    #import "H264ToYUVDeCoder.h"
  7.  
    #import "YUVToH264EnCoder.h"
  8.  
    #import "YUVPlayer.h"
  9.  
     
  10.  
    @interface ViewController ()<YUVPlayerDelegate>
  11.  
    @property(nonatomic, strong) UIImageView *imageView;
  12.  
    @end
  13.  
     
  14.  
    @implementation ViewController
  15.  
    @synthesize imageView;
  16.  
     
  17.  
    - (void)viewDidLoad {
  18.  
    [super viewDidLoad];
  19.  
    }
  20.  
     
  21.  
    /// 分离视频文件
  22.  
    /// - Parameter sender: UI 按钮
  23.  
    - (IBAction)onClickMediaFileSeparation:(id)sender {
  24.  
    // 输入文件
  25.  
    NSString * inFilePath = [PathTool bundlePath:@"input.mp4"];
  26.  
    // 输出文件(一般 mp4 音频流为 aac 格式 "aac" = "adts")
  27.  
    NSString * outFilePathAudio = [PathTool documentsPath:@"output"];
  28.  
    // 输出文件(一般 mp4 视频流为 h264 或者 hevc)
  29.  
    NSString * outFilePathVideo = [PathTool documentsPath:@"output"];
  30.  
    // 创建分离视频文件类
  31.  
    __block MediaFileSeparation *mediaFileSeparation = [[MediaFileSeparation alloc] init];
  32.  
    // 初始化数据,传入输入输出文件
  33.  
    int ret = [mediaFileSeparation init: inFilePath.UTF8String videoFilePath: (char *)outFilePathAudio.UTF8String audioFilePath: (char *)outFilePathVideo.UTF8String];
  34.  
    // 当返回值小于 0 时,初始化失败
  35.  
    if(ret < 0){
  36.  
    return;
  37.  
    }
  38.  
    dispatch_async(dispatch_get_global_queue(DISPATCH_BLOCK_DETACHED, 0), ^{
  39.  
    // 循环拆分数据
  40.  
    [mediaFileSeparation convertFrames];
  41.  
    // 结束
  42.  
    [mediaFileSeparation stop];
  43.  
    // 释放数据
  44.  
    mediaFileSeparation = nil;
  45.  
    });
  46.  
    }
  47.  
     
  48.  
    /// H264 解码 YUV
  49.  
    /// - Parameter sender: UI 按钮
  50.  
    - (IBAction)onClickH264ToYUV:(id)sender {
  51.  
    // 输入文件
  52.  
    NSString *inputFilePath = [PathTool documentsPath:@"output.hevc"];
  53.  
    // 输出文件
  54.  
    NSString *outputFilePath = [PathTool documentsPath:@"output.yuv"];
  55.  
    // 初始化文件管理器
  56.  
    __block FileTool *fileTool = [[FileTool alloc] init];
  57.  
    // 打开文件
  58.  
    int ret = (int)[fileTool open:inputFilePath.UTF8String model: FILE_MODE_READ];
  59.  
    // 小于 0,打开文件异常
  60.  
    if(ret < 0){
  61.  
    return;
  62.  
    }
  63.  
    // 初始化 H264 解码 YUV 管理器
  64.  
    __block H264ToYUVDeCoder *h264ToYUVDeCoder = [[H264ToYUVDeCoder alloc]init];
  65.  
    // 传入输入输出文件路径
  66.  
    ret = [h264ToYUVDeCoder init:inputFilePath.UTF8String outputFilePath:outputFilePath.UTF8String];
  67.  
    // 当返回值小于 0 时,初始化失败
  68.  
    if(ret < 0){
  69.  
    return;
  70.  
    }
  71.  
    //Stream #0:0: Video: hevc, yuv420p(tv), 848x480, 25 fps, 25 tbr, 1200k tbn, 25 tbc
  72.  
    // __weak ViewController *vc = self;
  73.  
    // 开启子线程,进行解码操作
  74.  
    dispatch_async(dispatch_get_global_queue(DISPATCH_BLOCK_DETACHED, 0), ^{
  75.  
    // 定义输入读取数据大小
  76.  
    int length = 1024 * 6;
  77.  
    uint8_t frame[length];
  78.  
    while(true){
  79.  
    // 读取输入数据
  80.  
    int size = (int)[fileTool read:frame length:length];
  81.  
    // 读完文件,则跳出循环
  82.  
    if(size <= 0){
  83.  
    break;
  84.  
    }
  85.  
    // 解码数据
  86.  
    [h264ToYUVDeCoder convertToYUV:frame withSize:length];
  87.  
    }
  88.  
    // 停止
  89.  
    [h264ToYUVDeCoder stop];
  90.  
    // 释放解码器数据
  91.  
    h264ToYUVDeCoder = nil;
  92.  
    // 释放文件资源
  93.  
    fileTool = nil;
  94.  
    });
  95.  
    }
  96.  
     
  97.  
    /// YUV 编码 H264
  98.  
    /// - Parameter sender: UI 按钮
  99.  
    - (IBAction)onClickYUVToH264:(id)sender {
  100.  
    // 输入文件
  101.  
    NSString *inputFilePath = [PathTool documentsPath:@"output.yuv"];
  102.  
    // 输出文件
  103.  
    NSString *outputFilePath = [PathTool documentsPath:@"output.h264"];
  104.  
    // 初始化文件管理器
  105.  
    __block FileTool *fileTool = [[FileTool alloc]init];
  106.  
    // 打开文件
  107.  
    int ret = (int)[fileTool open:inputFilePath.UTF8String model:FILE_MODE_READ];
  108.  
    // 当返回值小于 0 时,初始化失败
  109.  
    if(ret < 0){
  110.  
    return;
  111.  
    }
  112.  
    // 初始化 YUV 编码 H264 管理器
  113.  
    __block YUVToH264EnCoder *yuvToH264EnCoder = [[YUVToH264EnCoder alloc]init];
  114.  
    // 传入输出文件路径,宽和高
  115.  
    ret = [yuvToH264EnCoder init: outputFilePath.UTF8String width:848 height:480];
  116.  
    // 当返回值小于 0 时,初始化失败
  117.  
    if(ret < 0){
  118.  
    return;
  119.  
    }
  120.  
    // 开启子线程,进行编码操作
  121.  
    dispatch_async(dispatch_get_global_queue(DISPATCH_BLOCK_DETACHED, 0), ^{
  122.  
    // 定义输入读取数据大小,如果根据初始化得到的 yuv 数据大小,读取 610560 个数据点,fread 会卡住,只能分段读取进行缓存处理
  123.  
    int length = 1024 * 8;
  124.  
    uint8_t frame[length];
  125.  
    while (true) {
  126.  
    // 读取输入数据
  127.  
    int size = (int)[fileTool read:frame length:length];
  128.  
    // 读完文件,则跳出循环
  129.  
    if(size <= 0){
  130.  
    break;
  131.  
    }
  132.  
    [yuvToH264EnCoder convertCacheData:frame withSize:size];
  133.  
    }
  134.  
    // 停止
  135.  
    [yuvToH264EnCoder stop];
  136.  
    // 释放解码器数据
  137.  
    yuvToH264EnCoder = nil;
  138.  
    // 释放文件资源
  139.  
    fileTool = nil;
  140.  
    });
  141.  
    }
  142.  
     
  143.  
    /// 播放 YUV
  144.  
    /// - Parameter sender: UI 按钮
  145.  
    - (IBAction)onClickYUVPlayer:(id)sender {
  146.  
    // 输入文件
  147.  
    NSString *inputFilePath = [PathTool documentsPath:@"output.yuv"];
  148.  
    // 初始化文件管理器
  149.  
    __block FileTool *fileTool = [[FileTool alloc] init];
  150.  
    // 打开文件
  151.  
    int ret = (int)[fileTool open:inputFilePath.UTF8String model:FILE_MODE_READ];
  152.  
    // 返回值小于 0,打开文件失败
  153.  
    if(ret < 0){
  154.  
    return;
  155.  
    }
  156.  
    // 初始化 YUV 转 RGB 管理器
  157.  
    __block YUVPlayer *yuvPlayer = [[YUVPlayer alloc]init];
  158.  
    // delegate 回调
  159.  
    yuvPlayer.delegate = self;
  160.  
    // 添加 ImageView,用来播放画面
  161.  
    [self setupImageView];
  162.  
    // 传入宽高
  163.  
    ret = [yuvPlayer init:848 height:480];
  164.  
    // 返回值小于 0,初始化失败
  165.  
    if(ret < 0){
  166.  
    return;
  167.  
    }
  168.  
    // 开启子线程进行转码渲染
  169.  
    dispatch_async(dispatch_get_global_queue(DISPATCH_BLOCK_DETACHED, 0), ^{
  170.  
    // 定义输入读取数据大小
  171.  
    int length = 1024 * 8;
  172.  
    uint8_t frame[length];
  173.  
    while (true) {
  174.  
    // 读取输入数据
  175.  
    int size = (int)[fileTool read:frame length:length];
  176.  
    // 读完文件,则跳出循环
  177.  
    if(size <= 0){
  178.  
    break;
  179.  
    }
  180.  
    // 缓存并播放数据
  181.  
    [yuvPlayer cacheData:frame withSize:size];
  182.  
    }
  183.  
    // 释放播放器数据
  184.  
    yuvPlayer = nil;
  185.  
    // 释放文件资源
  186.  
    fileTool = nil;
  187.  
    });
  188.  
    }
  189.  
     
  190.  
    // ImageView
  191.  
    -(void)setupImageView{
  192.  
    if(!imageView){
  193.  
    CGFloat width = 320;
  194.  
    CGFloat height = 180;
  195.  
    CGFloat x = (self.view.width - width) * 0.5;
  196.  
    CGFloat y = (self.view.height - height) * 0.85;
  197.  
    // 显示画面
  198.  
    imageView = [[UIImageView alloc]initWithFrame:CGRectMake(x, y, width, height)];
  199.  
    imageView.backgroundColor = UIColor.blackColor;
  200.  
    imageView.contentMode = UIViewContentModeScaleToFill;
  201.  
    [self.view addSubview:imageView];
  202.  
    }
  203.  
    }
  204.  
     
  205.  
    // 更新 Image
  206.  
    - (void)showImage:(UIImage *)image{
  207.  
    dispatch_async(dispatch_get_main_queue(), ^{
  208.  
    self.imageView.image = image;
  209.  
    });
  210.  
    }
  211.  
     
  212.  
    @end
学新通

  3.2 效果图:

学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfhkabb
系列文章
更多 icon
同类精品
更多 icon
继续加载