Android使用FFmpeg 解码H264并播放(三)
上一节记录了Android使用FFmpeg解码H264的过程。这一节记录在Android上播放的过程。
问题描述
在开发中使用某摄像头的SDK,只能获取到一帧帧的 H264 视频数据,不知道视频流地址,需要自己解码出图像并播放。
问题解决
Android 播放解码后的视频帧
在Android上播放视频的总体思路是在Native层从 Surface 获取 到ANativeWindow,通过修改 ANativeWindow 的显示 buffer 来更新 Surface 的画面,这样一帧帧更新,最终看到的就是动画。
AVFrame 格式转化
一般从视频流里解析出的 AVFrame 的格式是 yuv 的,不能直接在 Android 的 nativewindow 上使用,需要先转换为 ARGB 或者 RGB565才行。
转码的代码网上很多,大致如下:
//1. 准备一个容器来装转码后的数据
AVFrame dst_frame = av_frame_alloc();
//在解码上下文使用extradata解析出第一帧图像后,ctx的width和height,pix_format 写入了实际的视频宽高,像素格式
dst_frame->width = ctx->width;
dst_frame->height = ctx->height;
//2. 转码为ARGB,来给NativeWindow显示
dst_frame->format = AV_PIX_FMT_ARGB;
//3. 根据输入图像和输出图像的信息(宽、高、像素),初始化格式转换上下文
//应该重复使用该上下文,不要每一帧都初始化一次
struct SwsContext * swsCtx = sws_getContext(
src_frame->width, src_frame->height,(enum AVPixelFormat) src_frame->format,
src_frame->width, src_frame->height,(enum AVPixelFormat) dst_frame->format,
SWS_FAST_BILINEAR, NULL, NULL, NULL);
//4. 初始化之前准备的dst_frame的buffer
int buffer_size = av_image_get_buffer_size((enum AVPixelFormat) dst_frame->format,src_frame->width,src_frame->height, 1);
uint8_t * buffer = (uint8_t *) av_malloc(sizeof(uint8_t) * buffer_size );
//5. 绑定dst_frame和新申请的buffer
av_image_fill_arrays(dst_frame->data, dst_frame->linesize, buffer,(enum AVPixelFormat) dst_frame->format, dst_frame->width, dst_frame->height, 1);
//6. 转码
sws_scale(swsCtx , (const uint8_t *const *) src_frame->data,src_frame->linesize, 0, src_frame->height,dst_frame->data, dst_frame->linesize);
渲染画面到 NativeWindow
- 从surface 中获取 NativeWindow
- 设置NativeWindow缓冲区格式
- 锁定NativeWindow缓冲区
- 写入数据到缓冲区
- 释放缓冲区
- 如果不再渲染了,释放NativeWindow
代码如下:
- H264FrameRender.java
/**
* 设置渲染的Surface
*/
public void setSurface(Surface surface) {if (nativeObject <= 0) {throw new IllegalStateException("H264FrameRender init failed");}_setSurface(this.nativeObject, surface);}
/**
* JNI
*/
private native void _setSurface(long nativeObject, Surface surface);
- JNI
JNIEXPORT void JNICALL Java_com_demo_H264FrameRender__1setSurface(JNIEnv *env, jobject instance,jlong nativeObject, jobject surface){//H264Render *render = (H264Render *) nativeObject;//获取到NativeWindow,ANativeWindow* window = ANativeWindow_fromSurface(surface);//绑定当前的window到native 层的render上,等待渲染if(render->window){ANativeWindow_release(render->window);render->window = NULL;}render->window = window;
}
- 渲染
解码器和格式转换器完成后会将调用渲染方法,将最终的数据渲染到NativeWindow
上。
/**
* @param render 渲染器
* @param data 解码和转换处理后的图像数据
* @param len data 的长度
* @param width 视频的宽
* @param height 视频的高
*/
void render_rend(NativeRender *render, signed char *data, size_t len, int width, int height) {if (render->window == NULL) {LOGE("window == null");return;}//设置缓冲区(宽,高,像素格式)ANativeWindow_setBuffersGeometry(render->window, width, height, WINDOW_FORMAT_RGBA_8888);//绘制int32_t locked = ANativeWindow_lock(render->window, render->buffer, NULL);if (locked == 0) {//由于window的 stride 和 frame 的 stride 不同,需要逐行拷贝uint8_t *dst = (uint8_t *) render->buffer->bits;uint8_t *src = dst_frame->data[0];int dest_stride = buffer->stride * 4;int src_stride = dst_frame->linesize[0];int height = dst_frame->height, h;for (h = 0; h < height; h++) {memcpy(dst + h * dest_stride,src + h * src_stride,(size_t) src_stride);}ANativeWindow_unlockAndPost(render->window);} else {LOGD("failed to lock window");}}
Android使用FFmpeg 解码H264并播放(三)相关推荐
- ffmpeg解码H264缺少帧的解决办法
最近用ffmpeg解码H264裸码流文件,发现解码总是少几帧.上网查了些资料,解决了. 当使用avcodec_decode_video2时,如果第三个参数的值为1,则表示完成一帧的解码,如果为0,表示 ...
- ffmpeg 切片花屏_利用ffmpeg解码H264,花屏,该如何解决
利用ffmpeg解码H264,花屏 UINT CMP4File::VideoCap_Thread_Fun(void* pParam) { CMP4File *pMP4File=(CMP4File*) ...
- 使用FFMPEG解码和OpenAL播放音乐
使用FFMPEG解码和OpenAL播放音乐 OpenAL是一个开源的音效库,然而这里只用它来播放音乐. FFMPEG负责把音乐解码并转换成指定的编码和采样率,然后送到OpenAL中播放. (已在w ...
- android下实时传输h264并播放
这周给安排了个任务,在android端读取H264原始视频数据,传一帧播一帧,播就播吧,还要Socket实时传输实时播,虽然并没有接触过,都无从下手,不过想到直播都是这么个形式,说明肯定是行得通的,而 ...
- Android使用MediaCodec解码H264视频解码器
前些日子有写了一篇博客[Android使用MediaCodec硬解码播放H264格式视频文件](http://blog.csdn.net/true100/article/details/5399293 ...
- FFmpeg解码H264裸流并转换成opencv Mat
感谢雷霄骅博士的在中文视频编解码的付出,http://blog.csdn.net/leixiaohua1020 最近要搞一些视频推流的事情,要解析H264裸流并且获取opencv格式的Mat数据给算法 ...
- (转)FFMPEG解码H264拼帧简解
http://blog.csdn.net/ikevin/article/details/7649095 H264的I帧通常 0x00 0x00 0x00 0x01 0x67 开始,到下一个帧头开始之前 ...
- android ffmpeg 解码,如何在Android用FFmpeg解码图像
白猪掌柜的 创建一个VideoPicture结构体用来保存解码出来的图像./** SDL_Lesson.c** Created on: Aug 12, 2014* Author: clarck*/#i ...
- FFmpeg解码的全能播放器
http://www.eoeandroid.com/thread-53373-1-1.html
- 使用ffmpeg解码音频sdl(push)播放
自定义播放器系列 第一章 视频渲染 第二章 音频(push)播放(本章) 第三章 音频(pull)播放 第四章 实现时钟同步 第五章 实现通用时钟同步 第六章 实现播放器 文章目录 自定义播放器系列 ...
最新文章
- APOC 15 Years Celebration
- Jsp获得Map中map.put(2, bb);此类的value值
- Eclipse插件安装的三种方法
- 查看mysql日志文件大小和数据库大小
- 企业绩效管理系统之平衡记分卡
- rsync 服务快速部署手册
- 全排列及相关扩展算法(七)——组合数的字典序(另含全章代码整理)
- java处理表单变量_jsp处理表单及JS和JAVA变量互传
- Atitit.spring体系结构大总结 1. Spel表达式解析	1 2. Srping mvc	1 3. Ioc	4 3.1. ApplicationContext在BeanFactory的基础
- Lattice FPGA 开发工具Diamond使用流程总结——安装
- 在龙芯3A3000上安装Gentoo
- Excel如何批量添加超链接
- [TypeScript]中字符和ASCII码转换
- stm32f107外设晶振8MHZ换成25MHZ 配置系统时钟72MHZ
- 如何让地面不起灰_水泥地面起灰怎么办?老师傅6招搞定了
- 网页引入谷歌字体_在网页中使用Google字体
- Linux即时通讯软件都有哪些?政企要怎么挑选?
- Spring Boot+Spring Security:记住我(Remember-Me): 基于简单加密token的方案 - 第25篇
- 两种常见的Vlan间通信的方式
- 几种网站压力测试工具调研与使用
热门文章
- 白平衡(WB:white balance)数值设置
- 美式期权定价python_美式期权baw定价的python实现
- 85人教版高中英语第一册第十一课 AT A TAILOR'S SHOP
- 计算机键盘运算符号输入,电脑上感叹号怎么打出来(电脑键盘符号大全)
- 黑客游戏(强烈推荐)攻防ctf
- html 自动切换tab栏,html 实现tab切换的示例代码
- 阙值,阈值,阀值,傻傻分不清
- MongoDB分片式高可用集群搭建
- acfun怎么下载视频
- 服装计算机辅助设计学什么,【计算机应用论文】服装设计的计算机辅助设计应用分析(共3905字)...