2014-03-19 60 views
5

這裏是我的問題, 我已經實現用Red5的服務器端應用程序,它發送H.264編碼的直播流,客戶端上的流被接收作爲字節[]
爲了它在Android客戶端解碼我按照Javacv-FFmpeg的庫。用於解碼的代碼如下從服務器接收Javacv:解碼H.264「活」流從RED5服務器未來的Android設備上

public Frame decodeVideo(byte[] data,long timestamp){ 
      frame.image = null; 
      frame.samples = null; 
      avcodec.av_init_packet(pkt); 
      BytePointer video_data = new BytePointer(data); 
      avcodec.AVCodec codec = avcodec.avcodec_find_decoder(codec_id); 
      video_c = null; 
      video_c = avcodec.avcodec_alloc_context3(codec); 
      video_c.width(320); 
      video_c.height(240); 
      video_c.pix_fmt(0); 
      video_c.flags2(video_c.flags2()|avcodec.CODEC_FLAG2_CHUNKS); 
      avcodec.avcodec_open2(video_c, codec, null)) 
      picture = avcodec.avcodec_alloc_frame() 
      pkt.data(video_data); 
      pkt.size(data.length); 
      int len = avcodec.avcodec_decode_video2(video_c, picture, got_frame, pkt); 
      if ((len >= 0) && (got_frame[0] != 0)) { 
      .... 
       process the decoded frame into **IPLImage of Javacv** and render it with **Imageview** of Android 
      } 
} 

數據如下具有
幾幀以下圖案
17 01 00 00 00 00 00 00 02 09 10 00 00 00 0F 06 00 01 C0 01 07 09 08 04 9A 00 00 03 00 80 00 00 16 65 EF 88 80 07 00 05 6C 98 90 00 ...

許多幀具有以下圖案
27 01 00 00 00 00 00 00 02 09 30 00 00 00 0C 06 01 07 09 08 05 9A 00 00 03 00 80 00 00 0D 77 41 9A 02 04 15 B5 06 20 E3 11 E2 3C 46 ....

對於解碼器的H.264編解碼器,解碼器輸出長度> 0,但got_frames = 0。
對於MPEG1編解碼器,解碼器輸出長度> 0且got_frames> 0,但輸出圖像爲綠色或失真。

然而以下javacv我可以解碼的本地文件的FFmpegFrameGrabber代碼(H.264編碼)與類似的代碼如上。

我不知道細節我很想念,又適合解碼器頭相關的數據操作或設定編解碼器。

任何建議,幫助表示讚賞。
在此先感謝。

回答

4

Atlast ...終於在大量RnD後工作。
我缺少的是視頻幀結構。視頻由「I」,「P」幀組成。「I」幀是信息幀,存儲關於下一個後續幀的信息。 「P」幀是相框,它擁有實際的視頻幀...
所以我需要解碼「P」中的「我」框架.. 所以最終的代碼是什麼如下

public IplImage decodeFromVideo(byte[] data, long timeStamp) { 
avcodec.av_init_packet(reveivedVideoPacket); // Empty AVPacket 
/* 
* Determine if the frame is a Data Frame or Key. IFrame 1 = PFrame 0 = Key 
* Frame 
*/ 
byte frameFlag = data[1]; 
byte[] subData = Arrays.copyOfRange(data, 5, data.length); 

BytePointer videoData = new BytePointer(subData); 
if (frameFlag == 0) { 
    avcodec.AVCodec codec = avcodec 
      .avcodec_find_decoder(avcodec.AV_CODEC_ID_H264); 
    if (codec != null) { 
     videoCodecContext = null; 
     videoCodecContext = avcodec.avcodec_alloc_context3(codec); 
     videoCodecContext.width(320); 
     videoCodecContext.height(240); 
     videoCodecContext.pix_fmt(avutil.AV_PIX_FMT_YUV420P); 
     videoCodecContext.codec_type(avutil.AVMEDIA_TYPE_VIDEO); 
     videoCodecContext.extradata(videoData); 
     videoCodecContext.extradata_size(videoData.capacity()); 

     videoCodecContext.flags2(videoCodecContext.flags2() 
       | avcodec.CODEC_FLAG2_CHUNKS); 
     avcodec.avcodec_open2(videoCodecContext, codec, 
       (PointerPointer) null); 

     if ((videoCodecContext.time_base().num() > 1000) 
       && (videoCodecContext.time_base().den() == 1)) { 
      videoCodecContext.time_base().den(1000); 
     } 
    } else { 
     Log.e("test", "Codec could not be opened"); 
    } 
} 

if ((decodedPicture = avcodec.avcodec_alloc_frame()) != null) { 
    if ((processedPicture = avcodec.avcodec_alloc_frame()) != null) { 
     int width = getImageWidth() > 0 ? getImageWidth() 
       : videoCodecContext.width(); 
     int height = getImageHeight() > 0 ? getImageHeight() 
       : videoCodecContext.height(); 

     switch (imageMode) { 
     case COLOR: 
     case GRAY: 
      int fmt = 3; 
      int size = avcodec.avpicture_get_size(fmt, width, height); 
      processPictureBuffer = new BytePointer(
        avutil.av_malloc(size)); 
      avcodec.avpicture_fill(new AVPicture(processedPicture), 
        processPictureBuffer, fmt, width, height); 
      returnImageFrame = opencv_core.IplImage.createHeader(320, 
        240, 8, 1); 
      break; 
     case RAW: 
      processPictureBuffer = null; 
      returnImageFrame = opencv_core.IplImage.createHeader(320, 
        240, 8, 1); 
      break; 
     default: 
      Log.d("showit", 
        "At default of swith case 1.$SwitchMap$com$googlecode$javacv$FrameGrabber$ImageMode[ imageMode.ordinal()]"); 
     } 

     reveivedVideoPacket.data(videoData); 
     reveivedVideoPacket.size(videoData.capacity()); 

     reveivedVideoPacket.pts(timeStamp); 
     videoCodecContext.pix_fmt(avutil.AV_PIX_FMT_YUV420P); 
     decodedFrameLength = avcodec.avcodec_decode_video2(videoCodecContext, 
       decodedPicture, isVideoDecoded, reveivedVideoPacket); 

if ((decodedFrameLength >= 0) && (isVideoDecoded[0] != 0)) { 
.... Process image same as javacv ..... 
} 
幀WRT信息

希望它西港島線幫助別人..