Android用FFmpeg解封装解码

1.解封装步骤

1.1 初始化操作

 //初始化解封装和编解码
 av_register_all();
 avcodec_register_all();
 //2、初始化网络
 avformat_network_init();

1.2 打开文件

 AVFormatContext *avc = NULL;
 char path[] = "/sdcard/test.mp4";
 int result = avformat_open_input(&avc, path, 0, 0);
 if (result != 0) {
	return env->NewStringUTF("打开失败");
 }

1.3 获取流信息

1.3.1 循环查找

int videoStream = 0;
int audioStream = 0;
for (int i = 0; i < avc->nb_streams; ++i) {
    AVStream *as = avc->streams[i];
    if (as->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
     videoStream = i;
    //视频数据
    }
    else if (as->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
    audioStream = i;
    //音频数据
     }
}

1.3.2 接口方法查找

//av_find_best_stream 例如音频数据
audioStream = av_find_best_stream(avc, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
AVStream *as = avc->streams[audioStream];

1.4 读取帧数据

 AVPacket *pkt = av_packet_alloc();
 AVFrame *frame = av_frame_alloc();
 for (;;) {
 int re = av_read_frame(avc, pkt);
 if (re != 0) {
    LOGW("读取到结尾");
	continue;
   }
 }

1.5 解码

1.5.1 软解码

avcodec_find_decoder 查找解码器

//1、查找解码器
AVCodec *vcodec = avcodec_find_decoder(avc->streams[videoStream]->codecpar->codec_id);

//2、解码器环境空间初始化
AVCodecContext *vc = avcodec_alloc_context3(vcodec);
//可以将AVStream参数直接复制到AVCodec中,默认单线程
avcodec_parameters_to_context(vc, avc->streams[videoStream]->codecpar);
//设置线程数
vc->thread_count = 1;//线程数
//3、打开解码器
result = avcodec_open2(vc, 0, 0);
if (result != 0) {//如果失败
   return env->NewStringUTF("avcodec_open2 failed");
}
//4、开始解码
//4.1发送到线程中解码
result = avcodec_send_packet(vc, pkt);
//4.2 要用for循环 保证能收到所有的数据
result = avcodec_receive_frame(vc, frame);

1.5.2 硬解码解码

通过名称查找解码器:avcodec_find_decoder_by_name,例如

//其他和1.5.1一样
AVCodec *vcodec = = avcodec_find_decoder_by_name("h264_mediacodec");

1.6 像素格式转换

//1、声明像素格式转换上下文
 SwsContext *sctx = NULL;
 int outWidth = 1280;
 int outHeight = 720;
 char *rgb = new char[1920 * 1080 * 4];//将空间复制给界面
//2、初始化像素格式转换上下文,在获取帧的for循环中操作
sctx = sws_getCachedContext(sctx,
                            frame->width,frame->height,(AVPixelFormat) frame->format,
                            outWidth, outHeight,AV_PIX_FMT_RGBA,
                            SWS_FAST_BILINEAR,0, 0, 0);
//3、数据转换
 uint8_t *data[AV_NUM_DATA_POINTERS] = {0};
 data[0] = (uint8_t *) rgb;
 int lines[AV_NUM_DATA_POINTERS] = {0};//一行宽度的大小
 lines[0] = outWidth * 4;//AV_PIX_FMT_RGBA 根据传进的像素格式获取大小
 int h = sws_scale(sctx,(const uint8_t **) frame->data,
 				  frame->linesize, 0,frame->height,
 				  data, lines);

1.7 音频格式重采样

//1.创建频重采样上下文初始化
char *pcm = new char[48000 * 4 * 2];
SwrContext *srctx = swr_alloc();
//2.设置上下文
srctx = swr_alloc_set_opts(srctx,
           					 //输出声道数
                               av_get_default_channel_layout(ac->channels),
           					 //输出格式
                               AV_SAMPLE_FMT_S16,
          					 //输入样本率不变
                               ac->sample_rate,
            				 //输入声道数
                               av_get_default_channel_layout(ac->channels),
            				 //输入声道数
                               ac->sample_fmt,
           					 //输出样本率
                               ac->sample_rate,
                               0, 0);

//3.初始化上下文                        
result = swr_init(srctx);
//4,在获取帧的for循环中操作
 uint8_t *out[2] = {0};//输出交错类型,非平面类型
 out[0] = (uint8_t *) pcm;
 //音频重采样
 int len = swr_convert(srctx,
                       out, frame->nb_samples,
                       (const uint8_t **) frame->data, frame->nb_samples);
  

1.8 手动回收对象

delete rgb;
delete pcm;
//释放内存
av_packet_unref(pkt);
//关闭上下文
avformat_close_input(&avc);

你可能感兴趣的:(FFmpeg)