如何在Android用FFmpeg+SDL2.0解码声音

一、创建一个VideoPicture结构体用来保存解码出来的图像;

如何在Android用FFmpeg+SDL20解码声音如何在Android用FFmpeg+SDL20解码声音


如何在Android用FFmpeg+SDL20解码声音


如何在Android用FFmpeg+SDL20解码声音


二、添加数据队列的初始化、添加以及读取的函数;

三、audio_decode_frame():解码音频;

四、audio_callback(): 回调函数,向SDL缓冲区填充数据;

五、创建刷新相关的函数;

六、添加显示函数;

七、分配显示输出内存空间;

八、解码线程,将,建立音频线,保存重要信息到数据结构中;

九、编写Main函数用来调用解码线程。

知识点延伸:

FFmpeg是一个开源跨的和音频流方案,属于自由,采用LGPL或GPL许可证(依据你选择的组件)。它提供了录制、转换以及流化音的完整解决方案。它包含了非常先进的音频/编解码库libcodec,为了保证高可移植性和编解码质量,libcodec里很多codec都是从头开发的。FFmpeg在Linux下开发,但它同样也可以在其它作系统环境中编译运行。

SDL2.0(Simple DirectMedia Layer)是一套开放源代码的跨多媒体开发库,使用C语言写成。SDL多用于开发游戏、模拟器、媒体播放器等多媒体应用领域。SDL内置了调用OpenGL的函数。SDL提供了数种控制图像、声音、输出入的函数,让开发者只要用相同或是相似的代码就可以开发出跨多个(Linux、Windows、Mac OS X等)的应用。

音视频编解码 原理

这个原理很复杂的。而且音频和视频的原理别很大,音视频不同标准之间的原理也有很多的别。不过基本上都是通过各种变换和模型来去除冗余,去除冗余的方法优劣决定了编码算法的好坏,不同的算法的计算复杂度也不同,很多音视频编解码都是压缩效果和当前条件实际可行性的某种折衷。

ffmpeg4,编码解码硬加速的实现

步骤基本上从网上抄袭就行。主要是3安装nv-codec-headers的版本,需要跟自己的驱动一致。我由于没有一致,安装cuda,安装其他的什么都没搞定,其中安装驱动还导致重装系统了,血的教训。

如何在Android用FFmpeg解码图像

这涉及到两个问题,一个是解码,另一个是显示,解码问题要先交叉编译ffmpeg,然后参考下面的解码流程

codec_register_all();

/

########################################

[1]

########################################

/

_register_all();

/

// Open video file

########################################

[2]

########################################

/

pFormatCtx = format_alloc_context();

if(format_open_input(&pFormatCtx, filename, NULL, NULL)!=0)

return -1; // Couldn't open file

// Retri stream rmation

/

########################################

[3]

########################################

/

if(format_find_stream_(pFormatCtx,NULL)<0)

return -1; // Couldn't find stream rmation

// Dump rmation about file onto standard error

// dump_format(pFormatCtx, 0, argv[1], 0);

// Find the first video stream

videoStream=-1;

for(i=0; i

nb_streams; i++)

if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO) {

videoStream=i;

break;

}if(videoStream==-1)

return -1; // Didn't find a video stream

// Get a pointer to the codec context for the video stream

pCodecCtx=pFormatCtx->streams[videoStream]->codec;

// Find the decoder for the video stream

pCodec=codec_find_decoder(pCodecCtx->codec_id);

if(pCodec==NULL) {

fprintf(stderr, "Unsupported codec!n");

return -1; // Codec not found

}// Open codec

if(codec_open2(pCodecCtx, pCodec,NULL)<0)

pFrame=codec_alloc_frame();

// Allocate an picture structure

picture_alloc(&picture, PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);

// Determine required buffer size and allocate buffer

img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);

if(img_convert_ctx == NULL)

{fprintf(stderr, "Cannot initialize the conversion context!n");

exit(1);

}// Read frames and se first five frames to disk

/

########################################

[4]

########################################

/

i=0;

dirtyRegion.set(android::Rect(0x3FFF, 0x3FFF));

while(_read_frame(pFormatCtx, &packet)>=0) {

// Is this a packet from the video stream?

if(packet.stream_index==videoStream) {

// Decode video frame

codec_decode_video2(pCodecCtx, pFrame, &frameFinished,

&packet);

// Did we get a video frame?

if(frameFinished) {

// Convert the image from its native format to RGB

sws_scale(img_convert_ctx,

pFrame->data, pFrame->linesize, 0, pCodecCtx->height,

picture.data, picture.linesize);

}}

// Free the packet that was allocated by _read_frame

_free_packet(&packet);

}pFrame为解码后的数据,将它显示在画布上,就完成了FFMEPG解码

Android视频播放器07-检测视频是否可以被硬解码

1、解码流程:

根据FFmpeg中视频的名称找到对应手机硬,如果存在则可以硬解码,

走硬解码流程;不存在就只能走软解码流程。

2、硬解码:

使用MediaCodec直接解码AVpacket,此时需要对AVPacket进行格式过滤,然后

MediaCodec解码后的数据用OpenGL ES渲染出来。

3、软解码:

直接用OpenGL ES 渲染YUV数据。

MediaCodecList.getCodecCount()支持的的SDK版本是16,buile.gradle中改 minSdkVersion 16

宏定义硬解码、软解码

iOS利用FFmpeg解码音频数据并播放

利用FFmepg解析并解码音频流数据,然后将解码后的音频数据送给Audio Queue以实现播放.

利用FFmpeg解析音频数据流, 利用FFmpeg解码音频数据为PCM格式. 利用Audio Queue Player实现音频数据播放.

本例以一个苹果原生相机录制的.MOV文件为例, 将该文件使用FFmpeg解析并解码,将解码后的数据放入传输队列中,然后开启audio queue player, 播放器在回调函数中轮循取出队列中的数据实现播放.

FFmpeg parse流程

FFmpeg解码流程

为了每次能够重新播放,这里需要标记当前是否为解码的帧数据,以重新启动播放器. 另一点是使用NSTimer等待音频数据放入队列再开始播放,因为audio queue是驱动播放模式,所以必须等音频数据放入传输队列再开始播放.

从Parse模块中可以获取当前文件对应FFmepg的上下文对象 AVFormatContext .因此音频流信息可以直接获取.

AVFrame 作为解码后原始的音视频数据的容器.AVFrame通常被分配一次然后多次重复(例如,单个AVFrame以保持从接收的帧)。在这种情况下,_frame_unref()将释放框架所持有的任何引用,并在再次重用之前将其重置为其原始的清理状态。

调用codec_send_packet将压缩数据发送给.后利用循环接收codec_receive_frame解码后的音视频数据.