Mpeg4解码流程

Mpeg4解码流程
    Mpeg4文件(包括avi视频文件以及mp3音频文件)解码过程由如下3个函数实现.
•    MPEG4_initial()    :    解码初始化。包括打开文件,设置有关硬件参数(如codec,
Dma等),解码参数初始化(如帧数统计,波特率设置,解码初始位置等),申请地址空间(如输出buffer等)。
•    MPEG4_continue()    :    解码过程的实体。主要完成读取输入,解码以及写输出的工
作,以帧为单位。如果返回1代表解码正常,可对其本身进行再调用,实现下一帧的解码。返回0则代表文件结束或者出现异常。
•    MPEG4_stop()    :    编码完成函数。这里需要完成对硬件的设置(如关闭codec
等),并释放内存空间等。
    Mpeg4解码库对于avi以及mp3的解码流程,都是由统一的一组initial() + n个continue() + stop()完成的。

    3个函数具体实现如下:
A.    MPEG4_initial()
Initial函数需要完成的工作有:
i.    判断输入文件是否存在
ii.    判断输入文件类型
iii.    根据输入文件类型设置控制参数(如:音频流格式,视频流格式,静音设置,暂停设置,是否显示视频解码结果,mp3是否做频谱分析,视频播放是否显示时间等等)
iv.    根据文件类型做初始化:
a)    AVI文件:
1)    初始化文件结构pAviFile   
2)    设置有关参数。如帧数统计,FPS等
3)    初始定位。设定开始解码的位置。
4)    判断音频的编码格式,并分别调用其initial函数。
b)    MP3文件:
1)    设置有关参数,如bps,帧数统计等。
2)    打开mp3文件pMp3File
3)    初始定位。设定开始解码的位置。
4)   
B.    MPEG4_continue()
Continue()函数很明显的是解码过程中最重要的也是最复杂的一个环节。Continue函数考虑的问题主要有如下几个:
i.    如何实现音频的连续播放
音频的pcm值是需要以恒定的速率送至codec的,否则人耳可以清楚的分辨
出杂音。因此,保证音频解码和播放的连贯性是最重要的。在系统中,我们使用了DMA完成codec的写工作,而cpu在同时完成音频的解码工作。并且,用一组标志位来实现dma、codec播放和cpu的解码同步。
ii.    如何实现音频视频的同步
视频文件中,音频和视频的同步是十分重要的。否则整个视频文件的解码和播
放可以被认为是失败的。在假定文件本身是同步的情况下,我们实现音频视频同步    方式就是:用音频来控制视频,以实现音频和视频的同步。我们可以通过音频解码
中的某些参数计算出音频已经播放的时间,然后通过视频的有关参数我们可以计算得到视频相对的帧的编号,从而控制视频的输出。
iii.    如何实现暂停
由于mpeg4编码基于的是palos操作系统,这个微操作系统是无法将程序本身挂起,因此continue函数必须考虑如何实现pause功能。目前的 做法是,continue本身并不pause,还是在不停的进行自调用。而在continue函数的最开始加入IS_PAUSE标志位的判断, 如果该标志位为1,则直接返回1return,进行下一次自调用。
iv.    如何实现其他功能
mpeg4解码中还需要实现其他功能,比如音量调整,音效调整等。这些功能在
整个解码设计的时候就已经变成几个系数集成到了continue中的解码函数中。因此
这些附加功能与continue函数的调度和结构没有关系。操作系统只需要设置整个decoder中的几个全局变量就可实现这些功能。

C.    MPEG4_stop()
Stop函数完成的主要工作有:
i.    参数设定。如结束参数等。因为解码并不一定时continue函数返回0时才结束,用户可以通过按键来中断文件播放,因此,控制参数必须在这里也进行设置,尽管有的参数可能已经在continue函数中设置过,比如IS_AUDIO_END。
ii.    关闭有关硬件(如codec),
iii.    根据文件类型调用stop:
a)    AVI文件:释放pAviFile,关闭文件,并根据音频格式做相应的stop动作。
b)    MP3文件:关闭文件并调用mp3_stop();

Mpeg4解码过程中的技术难点和重点

A.    多文件格式,多音频流格式的实现
•    多文件格式的实现
mpeg4 decoder中包含了音频文件和视频文件的decoder。也就是说,同样的一套接口需
要完成AVI文件和MP3文件的解码。Decoder内部必须判断文件的类型,并且调用不同的接口。
    系统声明了几个全局变量IS_AVI_MODE、IS_MP3_MODE,通过这2个参数来控制解码程序调用不同的解码函数。
•    多音频格式的实现
音频格式种类繁多,比较通用的有AMR,mp3,adpcm和pcm。因此,在解码avi文件
时,必须判断音频的编码器,并调用响应的解码器进行解码。在视频解码接口pAviFile初始化后,我们可以通过这个结构的一个参数pAviFile->a_fmt来判断音频的编码格式,并调用响应的解码器进行解码。比如下面的代码:

    值得特别注意的是,不同的音频解码器对输出buffer的大小要求是不一样的。或者说,每一次调用continue所产生的解码后的pcm值的个数是不一 样的。因此,在实现音频视频同步以及调用DMA往CODEC写pcm值的时候,必须正确设置有关的参数。具体操作稍后将详细说明。

B.    AVI文件音频视频解码/播放的同步控制
视频文件实时解码播放时,音频视频同步是一个非常重要的问题,也是技术上的一个
难点。目前我们系统中采取的方案是通过音频来控制视频。
    另外,必须控制的另外一个同步就是音频/视频解码和播放的同步。为了保证播放的实时性,系统就必须保证播放的同时进行解码工作,并且通常来说,解码一般是 超前于播放几个帧。同时,由于解码时写入解码结果的输出buffer和播放时的输入buffer实际上是同一块buffer,因此对这组buffer我们 必须进行严格的控制,以保证buffer数据的正确性。
                                    图2
总的说来,我们需要控制4个“进程”,实现他们之间的同步。这4个进程分别是:视频解码,视频播放,音频解码,音频播放。对照上图,我们详细说明同步将如何实现。.

1)    解码和播放的同步
对于音频播放和解码,以及视频播放和解码的同步控制是类似的。解码过程中,有3个实体,解码器,播放器,以及缓存的buffer。缓存的目的在于解码和播 放之间不用完全同步。解码可以先于播放,这样可以保证,当不可抗拒的因素导致解码短时间内停顿的时候,播放进程还是有足够的数据可以用于播放。该 Buffer相当于一个循环数组,我们要求播放指针不能超过解码指针(否则读取的数据将会无效),同时,我们还要求解码指针不能移动过快,从而移动一圈后 超过播放指针(否则解码程序将覆盖尚未播放的buffer)。为了实现这个控制,对于每个buffer我们都由一个flag。程序初始时,每个flag都 设置为BUFFER_FREE。
解码程序如果检测到解码指针对应的buffer标志位为FREE时进行解码程序,将解码后的数据写入buffer以后,将该buffer的标志设为BUFFER_WAIT,同时将解码指针后移;如果解码指针指向的buffer是其他状态,则本次调度不执行解码。
播放程序如果检测到buffer的标志位为BUFFER_WAIT,则开始播放程序,并将BUFFER的标志位设为BUFFER_BUSY。当播放结束 后,将BUFFER的标志位写成BUFFER_FREE并将播放指针后移动;如果buffer指针指向的buffer标志位不是BUFFER_WAIT, 则本次调度不执行播放。值得一提的是,由于音频播放要求的连贯性,我们必须用DMA来实现音频的播放。因此,播放程序的启动是在普通的代码中,而播放后的 处理工作(即写BUFFER_FREE和指针后移的过程则需要放在DMA处理完数据产生的中断中进行)。
    通过上述的buffer标志位控制,我们就可以实现解码和播放的同步执行,并且,我们保证解码始终先于播放,且优先的帧数不会超过buffer的数目。

2)    音频和视频的同步
在文件的播放过程中,音频的速率是一定的,不可增快也不可减慢,因此,用音频控制
视频实现同步是很自然的。在视频文件的播放控制中,我们必须解决下面2个问题:
    a.如果视频快于音频,如何控制视频的播放速度
    b.如果视频慢于音频,如何丢帧,使得视频赶上音频
    对于这2个问题,我们有着2种不同的解决方案。请注意,这2种方案都是基于一条调度的原则:如果音频buffer出现free的情况,无条件执行音频解码程序。
a.    视频速度的控制
首先我们必须意识到视频解码和播放的相互制约。因为解码是否执行取决于播放程序是
否把buffer的标志位写成BUFFER_FREE,而播放之否执行则以来于解码程序是否把buffer的标志位写成BUFFER_WAIT。因此,控 制播放或者解码,都能控制整个视频方面的解码速度。由于视频和音频的同步直观上是播放上的同步,因此,我们通过音频已经播放的帧数来控制视频允许播放的帧 数。如果视频速度过快,则不允许其播放,自然也阻碍了解码的进行,从而实现对整个视频解码播放进程的速度控制。具体的做法是,通过音频的采样率和每帧包含 的sample数目等参数计算出当前音频已经播放的时间,然后通过视频的FPS来计算视频应当播放的帧数actualFrameCount。如果当前实际 播放的帧数displayFrameCount大于等于应该播放的帧数actualFrameCount,则调度时不执行视频的播放。直到音频播放了足够 的帧数,对视频播放产生了新的需求时候,播放程序才会继续。这样,我们就有效的控制了视频的播放速度。
b.    视频丢帧的实现
必须考虑的另外一种情况是:由于系统一直保证音频的解码,有可能在播放某些画面切
换很快的视频文件时,系统来不及解码视频的情况。因此,为了使得视频能赶上音频,我们必须抛弃一些视频的帧。当然,由于mpeg4decoder的特性, 除了关键帧以外,其他帧数的解码结果必须依赖于上一帧的解码结果。因此,我们丢弃的只是每一帧yuv转换以及lcd输出的一部分。   
    具体的实现方式如下:当需要播放的帧数actualFrameCount大于实际已经播放的视频帧数displayFrameCount+buffer数 目时,我们可以认为是系统无法解码足够的视频帧数。如果出现这种情况,在decode完毕,处理yuv之前,直接将解码后结果抛弃,并将当前解码 buffer的标记设置为BUFFER_SKIP,并将解码指针后移动,这样就减少了该帧的yuv转换操作。当播放程序看到BUFFER_SKIP时,直 接将buffer标记位设成BUFFER_FREE(请注意,这一步必须进行,因为buffer中是无效的数据),再将播放指针后移动,然后把 displayFrameCount加1(跟正常的播放操作一样)。这样就减少了一次LCD播放。
    可以看到,抛弃一帧意味着减少了一次YUV转换以及一次LCD输出(目前输出是基于cpu而非基于DMA)。因此,一次跳帧意味着节省3个左右的 mips。而可以看到的是,我们所谓的跳帧只是把一帧设置为无效,但是这一帧还是跟正常的播放帧一样存在于整个视频buffer序列中,因此不会影响到视 频和音频的同步。

c.    视频丢帧的实现
最后,我们来看看mpeg4Decoder中的continue具体如何实现音频视频同步。如下图:

 

C.    解码参数实时设置的实现
在mpeg4/mp3解码过程中有很多需要实时调整的地方,比如音量,音效,静音,暂停
等等。下面介绍下这些设置如何实现:
1)    暂停:暂停实现方式比较简单。系统声明了一个全局变量IS_PAUSE。如果系统接受到按键,则把这个参数取反。当continue函数判断该标志位置1 时,直接跳出函数,等待下一次调度。需要注意的是,如果音频buffer开很大,那么暂停以后可能需要一段时间音频才会停下来(dma会搬完所有的 buffer才会停止)。因此,我们在dma中断程序中也加入对IS_PAUSE的判断。如果dma中断发现pause,则播放完当前buffer之后, 只作播放指针的便宜,而不开启下一此dma调用。下一次调用将发生在pause结束后的continue函数中。
2)    静音:系统接受到静音按键以后,将IS_MUTE参量取反。音频文件在最后输出pcm值时,看到该变量会将所有pcm置0。
3)    音效:系统接受到音效按键,会设置eq_type的值。Mp3解码过程中会根据该值输出不同的pcm值。
4)    音量:系统接受到音量按键直接调用codec接口,与解码程序无关。
5)    快进/倒退:系统根据当前已经播放的帧数计算出播放的时间,才读取全局变量获得便宜的时间,将这2个时间相加得到当前时间。再在这个时间的基础上加上或者 减去step的时间,获得目标时间。得到目标时间以后,将当前播放程序stop掉,并按照目标时间initial,然后继续播放即可。这个过程只是通过 stop和initial改变了解码程序的一些变量值,对于外部os而言,看上去还是不断continue的过程,只是在continue中间插入了一段 skip或者backward操作。
可以看到,所有功能的实现都不影响到播放一个文件根据 initial + n个conitnue +
stop调用的原则。区别只是在2个continue之间加入了需要处理的消息响应函数。

D.    Mp3频谱分析的实现
大多数音频或者视频的编码和解码都是基于频域的。因此,在解码过程中肯定可以获取
频域信息。比如mp3音效设置,就是在imdct之前对各个子带值乘了不同的系数。
    Mp3频谱分析也是如此。在解码到某个过程时获取32个子带,32*18条频线的值,然后根据一定算法五颜六色显示到屏幕固定位置固定大小的地方即可。
您正在看的文章来自博研联盟 http://mse.bylm.net/forum ,原文地址:http://mse.bylm.net/forum/read-htm-tid-270649.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值