Android视频流解码

一、硬解码

步骤:

1.创建MediaCodec:如 MediaCodec.createDecoderByType(keyMime);

2.configure codec:配置format,surface等参数

3.start codec

4.从codec的inputBuffer缓冲区获取一个索引,用于传递解码前的数据(比如h264数据):dequeueInputBuffer,注意如果返回-1说明当前inputBuffer缓冲区已满了,不接收新的数据输入
5.如果获取的inputBufferIndex大于0,说明有可用的输入缓冲区,通过以下接口获取一个空的inputBuffer:
api 21以下:mediaCodec.getInputBuffers()[inputBufferIndex]
api 21以上:mCodec.getInputBuffers(inputBufferIndex);    

6.从视频容器(如MP4)demux一个数据,填充到inputBuffer,如:mExtractor.readSampleData(inputBuffer, 0);
7.现在inputBuffer已经填充了数据了,通过queueInputBuffer接口将inputBuffer送入decode队列
8.

接下来调用dequeueOutputBuffer,获取解码器的输出。注意,这个函数传递以下参数:

8.1 MediaCodec.BufferInfo:这个是我们作为入参传入的,传入的时候是一个空的BufferInfo。当解码器dequeueOutputBuffer获取到输出的时候,会将解码器输出数据的metadata填充到这个对象里面

8.2 timeoutUs自然就是等待解码器输出的超时时间了
8.3 这个函数的返回值是:成功解码的output buffer的index,可以根据这个index获取到output buffer
9.根据outputBufferIndex,从解码器输出缓冲区中获取一个outputBuffer
api 21以下:mediaCodec.getOutputBuffers()[outputBufferIndex]
api 21以上:mCodec.getOutputBuffer(outputBufferIndex);


10.有了解码的输出数据outputBuffer和数据的metadata(包括offset,pts等信息),就得到了完整的解码数据了
 

二、软解码(FFMPEG解码)

1.首先要注册解码器  

2.创建ffmpeg codec:调用avcodec_find_decoder:在ffmpeg中是根据codecid(aac,h264等注册的id)寻找合适的decoder,返回AVCodec(存储编解码器信息的结构体)对象

3.创建decode的context:avcodec_alloc_context3,这函数返回的codecContext包含解码器所需要的各种配置信息,比如
对于aac decode,context可以用来设置sample_rate,channels,profile等
对于h264 decode,context可以用来设置width,height等、
4.调用avcodec_open2:用已经配置好的decoder的context,来configure解码器codec
5.调用av_init_packet(AVPacket *pkt);初始化一个pkt用于接收待解码的数据

6.用demux输出的数据,填充pkt的data,设置pkt的flag(是否包含key frame等)
7.调用avcodec_send_packet将填充满的pkt,发送给解码器
8.调用

avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,
              int *got_picture_ptr,
              const AVPacket *avpkt);

;从解码器接收decode后的数据,填充到AVFrame中。

通过以上函数就能够得到解码后的数据了,之后根据需要,还可以继续处理:

9.对于video数据,从AVFrame中,拷贝decoded的数据成YUV格式(I420),到uint8_t数组

10.通过OpenGL的shader可以将YUV420数据画到SurfaceView的output surface上,进行渲染

 

 

Android解码MJPEG格式的视频流,你可以使用以下步骤: 1. 添加必要的依赖项。在你的Android项目中,添加对OpenCV的依赖项,以便使用其图像处理功能。在项目的build.gradle文件中,添加以下依赖项: ```groovy implementation 'org.opencv:opencv-android:3.4.13' ``` 2. 创建一个自定义的SurfaceView类,并实现SurfaceHolder.Callback接口,以监听SurfaceView的生命周期事件。 ```java public class MJPEGSurfaceView extends SurfaceView implements SurfaceHolder.Callback { private MJPEGDecoder mjpegDecoder; public MJPEGSurfaceView(Context context) { super(context); getHolder().addCallback(this); } @Override public void surfaceCreated(SurfaceHolder holder) { // 在Surface创建时初始化解码器 mjpegDecoder = new MJPEGDecoder(holder.getSurface()); mjpegDecoder.startDecoding(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // 在Surface尺寸发生变化时更新解码器 mjpegDecoder.updateSurface(holder.getSurface()); } @Override public void surfaceDestroyed(SurfaceHolder holder) { // 在Surface销毁时停止解码器 mjpegDecoder.stopDecoding(); } } ``` 3. 创建一个MJPEGDecoder类,负责接收和解码MJPEG格式的视频流。 ```java public class MJPEGDecoder { private Surface surface; private boolean isDecoding; public MJPEGDecoder(Surface surface) { this.surface = surface; isDecoding = true; } public void startDecoding() { // 开始解码线程 new Thread(new Runnable() { @Override public void run() { while (isDecoding) { // 从MJPEG视频流中获取数据并解码 byte[] frameData = getFrameDataFromStream(); // 使用OpenCV解码图像 Bitmap frame = decodeFrame(frameData); // 将解码后的帧绘制到Surface上 drawFrameToSurface(frame); } } }).start(); } public void updateSurface(Surface surface) { this.surface = surface; } public void stopDecoding() { isDecoding = false; } private byte[] getFrameDataFromStream() { // 从网络或其他来源获取MJPEG视频流数据 // 返回帧的字节数组 } private Bitmap decodeFrame(byte[] frameData) { // 使用OpenCV解码MJPEG帧 Mat frameMat = Imgcodecs.imdecode(new MatOfByte(frameData), Imgcodecs.IMREAD_UNCHANGED); Bitmap frameBitmap = null; if (!frameMat.empty()) { frameBitmap = Bitmap.createBitmap(frameMat.cols(), frameMat.rows(), Bitmap.Config.ARGB_8888); Utils.matToBitmap(frameMat, frameBitmap); } return frameBitmap; } private void drawFrameToSurface(Bitmap frame) { if (frame != null) { Canvas canvas = surface.lockCanvas(null); if (canvas != null) { canvas.drawBitmap(frame, 0, 0, null); surface.unlockCanvasAndPost(canvas); } } } } ``` 4. 在你的Activity中使用自定义的MJPEGSurfaceView来显示MJPEG视频流。 ```java public class MainActivity extends AppCompatActivity { private MJPEGSurfaceView surfaceView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); surfaceView = findViewById(R.id.surface_view); } } ``` 确保在布局文件中添加一个MJPEGSurfaceView元素: ```xml <com.example.MJPEGSurfaceView android:id="@+id/surface_view" android:layout_width="match_parent" android:layout_height="match_parent" /> ``` 这样,你就可以在Android解码和显示MJPEG格式的视频流了。请确保根据你的需求和网络库进行必要的调整和配置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值