Mediacodec获得视频流,写入H264文件

Reference:https://github.com/ele828/blog/blob/master/source/_posts/Android%E5%B1%8F%E5%B9%95%E7%9B%B4%E6%92%AD%E6%96%B9%E6%A1%88.md
while (mIsCapturing) {
         // get encoded data with maximum timeout duration of TIMEOUT_USEC(=10[msec])
            encoderStatus = mMediaCodec.dequeueOutputBuffer(mBufferInfo, TIMEOUT_USEC);
            if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
                // wait 5 counts(=TIMEOUT_USEC x 5 = 50msec) until data/EOS come
               
            } else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
               if (DEBUG) Log.v(TAG, "INFO_OUTPUT_BUFFERS_CHANGED");
                // this shoud not come when encoding
                encoderOutputBuffers = mMediaCodec.getOutputBuffers();
            } else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
               if (DEBUG) Log.v(TAG, "INFO_OUTPUT_FORMAT_CHANGED");
               // this status indicate the output format of codec is changed
                // this should come only once before actual encoded data
               // but this status never come on Android4.3 or less
               // and in that case, you should treat when MediaCodec.BUFFER_FLAG_CODEC_CONFIG come.
                if (mMuxerStarted) {   // second time request is error
                    throw new RuntimeException("format changed twice");
                }
            // get output format from codec and pass them to muxer
            // getOutputFormat should be called after INFO_OUTPUT_FORMAT_CHANGED otherwise crash.
                final MediaFormat format = mMediaCodec.getOutputFormat(); // API >= 16
                ByteBuffer spsb = format.getByteBuffer("csd-0");
            	ByteBuffer ppsb = format.getByteBuffer("csd-1");
            
            if (spsb != null) {
               byte[] sps = new byte[spsb.capacity()];
               //spsb.position(4);
               spsb.get(sps, 0, sps.length);
               
               try{
                  outputStream.write(sps);
                  //outputStream.write(pps);
               }catch (IOException e){
                  e.printStackTrace();
               }
            }
            if (ppsb != null) {
               byte[] pps = new byte[ppsb.capacity()];
               ppsb.get(pps);
          
               try{
                  outputStream.write(pps);
                  //outputStream.write(pps);
               }catch (IOException e){
                  e.printStackTrace();
               }
            }

            mTrackIndex = muxer.addTrack(format);
                   mMuxerStarted = true;
                   if (!muxer.start()) {
                      // we should wait until muxer is ready
                      synchronized (muxer) {
                         while (!muxer.isStarted())
                  try {
                     muxer.wait(100);
                  } catch (final InterruptedException e) {
                     break LOOP;
                  }
                      }
                   }
            } else if (encoderStatus < 0) {
               // unexpected status
               if (DEBUG) Log.w(TAG, "drain:unexpected result from encoder#dequeueOutputBuffer: " + encoderStatus);
            } else {
                final ByteBuffer encodedData = encoderOutputBuffers[encoderStatus];
                if (encodedData == null) {
                   // this never should come...may be a MediaCodec internal error
                    throw new RuntimeException("encoderOutputBuffer " + encoderStatus + " was null");
                }
                if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
                   // You shoud set output format to muxer here when you target Android4.3 or less
                   // but MediaCodec#getOutputFormat can not call here(because INFO_OUTPUT_FORMAT_CHANGED don't come yet)
                   // therefor we should expand and prepare output format from buffer data.
                   // This sample is for API>=18(>=Android 4.3), just ignore this flag here
               if (DEBUG) Log.d(TAG, "drain:BUFFER_FLAG_CODEC_CONFIG");
               mBufferInfo.size = 0;
                }

                if (mBufferInfo.size != 0) {
                   // encoded data is ready, clear waiting counter
                  count = 0;
                    if (!mMuxerStarted) {
                       // muxer is not ready...this will prrograming failure.
                        throw new RuntimeException("drain:muxer hasn't started");
                    }
                    // write encoded data to muxer(need to adjust presentationTimeUs.
               byte[] outData = new byte[mBufferInfo.size];
               
               encodedData.get(outData);
               try {
                  outputStream.write(outData,0,outData.length);
                  outputStream.flush();
               } catch (IOException e) {
                  e.printStackTrace();
               }
               mBufferInfo.presentationTimeUs = getPTSUs();
                       muxer.writeSampleData(mTrackIndex, encodedData, mBufferInfo);
               prevOutputPTSUs = mBufferInfo.presentationTimeUs;
                }
                // return buffer to encoder
                mMediaCodec.releaseOutputBuffer(encoderStatus, false);
                if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
                   // when EOS come.
                      mMuxerStarted = mIsCapturing = false;
               break;      // out of while
                }
            }
        }//end while
	将视频数据流写入文件中,重点是H264的PPS和SPS部分,这部分在 MediaCodec.INFO_OUTPUT_FORMAT_CHANGED 里面
通过获得ByteBuffer,然后获得csd-0和csd-1两个部分,获得最终的解码信息。之后再将视频帧数据写入文件即可。
	视频播放器建议使用PotPlayer,完美播放H264文件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值