FFempeg绘制视频

从开始的解封装,初始化解码器,解码,接受,所有的东西都看不到实际的效果,接下来就是展示视频音频的步骤了。
一:音频的重采样

在数据接受后判断音频流还是视频流,在音频流中做处理

 SwrContext *actx=swr_alloc();
        //2p:通道格式默认 声道数 3p:输出格式
        actx = swr_alloc_set_opts(actx, av_get_default_channel_layout(2), AV_SAMPLE_FMT_S16,ac->sample_rate,
                                  av_get_default_channel_layout(ac->channels), ac->sample_fmt, ac->sample_rate,0,0);
        re = swr_init(actx);
        char *pcm = new char[48000*4*2];

pcm是缓冲区,actx是频重采样上下文。
swr_alloc_set_opts是上下文参数配置包括原数据参数和转换参数,声道数可以根据实际的channels设置,但通常只需要双声道兼容大部分的声卡。

下面是进行转换的操作,主要借助swr_convert

 uint8_t *out[2];
                    out[0]=(uint8_t *)pcm;
                    //out 输出数据 p3:一个frame中有多少个音频样板
                    int len=swr_convert(actx,out,frame->nb_samples,
                                        (const uint8_t **)frame->data,frame->nb_samples);
                    //通道输出样品数
                    LOGW("swr_convert = %d", len);

二:视频像素格式和尺寸转换

和音频相同,先对转换上下文初始化,设置转换后的视频宽高为1920和720

  //初始化像素格式转换的上下文
        SwsContext *vctx=NULL;
        //输出宽高
        LOGW("the video with:%d",vc->width);
        int outWidth=1920;
        int outHeight=720;
        char *rgb = new char[1920*1080*4];

上下文初始化代码:

 vctx = sws_getCachedContext(vctx,frame->width,frame->height,(AVPixelFormat) frame->format,
                                                outWidth,
                                                outHeight,
                                                AV_PIX_FMT_RGBA,
                                                SWS_FAST_BILINEAR,
                                                0, 0, 0);

转换的像素格式为AV_PIX_FMT_RGBA,SWS_FAST_BILINEAR是进行转换的算法。后面参数不需要。

下面进行转换操作:

 uint8_t *data[AV_NUM_DATA_POINTERS] = {0};
                        data[0] = (uint8_t *) rgb;
                        int lines[AV_NUM_DATA_POINTERS] = {0};
                        lines[0] = outWidth * 4;
                        int h = sws_scale(vctx,
                                          (const uint8_t **) frame->data,
                                          frame->linesize, 0,
                                          frame->height,
                                          data, lines);

测试用了两个视频,出现一个转换失败的情况:
转换失败的:原视频vc->width=1920 转换尺寸为1920 转换尺寸换成1080成功
转化成功的:原视频vc->width=1080 转换尺寸为1280 转换尺寸换成1080成功
暂时不清楚具体原因是否是元数据的尺寸导致的。
如果h 转换后的高度是目标高度则转换成功。

三:视频绘制
android中视频的绘制借助GLSurfaceView完成,作为视频播放的容器,也需要使用到android底层的C++库完成视频绘制。
首先定义一个继承GLSurfaceView的PlayView:

public class PlayView extends GLSurfaceView implements Runnable, SurfaceHolder.Callback {
    public PlayView(Context context) {
        super(context);
    }

    public PlayView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public void run() {
          Open("/sdcard/LL迷窟-04.mp4",getHolder().getSurface());

    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        new Thread(this).start();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    }

    public native void Open(String url, Object surface);
}

设置到布局,这里新定义了native方法Open,参数是视频路径和Surface。
需要配置Android相关的库


初始化窗口

 //初始化窗口客服端传递的容器 Android 相关的底层库
        ANativeWindow *nwin = ANativeWindow_fromSurface(env, surface);
        ANativeWindow_setBuffersGeometry(nwin, outWidth, outHeight, WINDOW_FORMAT_RGBA_8888);
        ANativeWindow_Buffer wbuffer;
 完成数据拷贝:
  if (h > 0) {
                            ANativeWindow_lock(nwin,&wbuffer,0);
                            uint8_t *dst=(uint8_t*)wbuffer.bits;
                            //vWidth * vHeight * 4 RGBA8888 四个字节
                            //拷贝数据
                            memcpy(dst, rgb, outWidth * outHeight * 4);
                            ANativeWindow_unlockAndPost(nwin);
                        }

注意 memcpy(dst, rgb, outWidth * outHeight * 4);方法可能引起视频界面不对齐的问题、
竖屏情况下显示有问题:

横屏的话正常:

终于看见画面了,但是没有声音。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值