1. 程式人生 > >Live555+FFMPEG+ddraw實現H264碼流接收,解碼,顯示

Live555+FFMPEG+ddraw實現H264碼流接收,解碼,顯示

1)H264碼流接收採用的是live555,live555會將sps,pps,I幀,p幀都是單獨的包過來的,在接收到Buffer,需要對它進行組成幀,live555自己支援I幀和P幀的組幀的,但是我們交給ffmpeg前,必須對在每幀之前插入00 00 00 01開始碼,同時如果是I幀,必須將sps,pps,I幀同時交給ffmpeg才能解碼的,所以對live555的Buffer的進行組幀;

live555的重點工作是拿到Buffer,可以參考OpenRtsp和RtspClient兩個例子,OpenRtsp中有一個FileSink和H264VideoFileSink,RtspClient中有個DummySink,可以修改這個Sink,在這個Sink中進行組幀,然後呼叫ffmpeg解碼;

class DummySink: public MediaSink {
public:
 static DummySink* createNew(UsageEnvironment& env,
  MediaSubsession& subsession, // identifies the kind of data that's being received
  char const* streamId = NULL); // identifies the stream itself (optional)

private:
 DummySink(UsageEnvironment& env, MediaSubsession& subsession, char const* streamId);
 // called only by "createNew()"
 virtual ~DummySink();

 static void afterGettingFrame(void* clientData, unsigned frameSize,
  unsigned numTruncatedBytes,
 struct timeval presentationTime,
  unsigned durationInMicroseconds);

 void afterGettingFrame(unsigned frameSize, unsigned numTruncatedBytes,
 struct timeval presentationTime, unsigned durationInMicroseconds);

private:
 // redefined virtual functions:
 virtual Boolean continuePlaying();

private:
 u_int8_t* fReceiveBuffer;
 MediaSubsession& fSubsession;
 char* fStreamId;
};

2)採用ffmpeg進行解碼;這個沒有什麼可說的,我前面的例子裡面有;

我們可以改寫:

void DummySink::afterGettingFrame(unsigned frameSize, unsigned numTruncatedBytes,
struct timeval presentationTime, unsigned /*durationInMicroseconds*/) {

 unsigned char const start_code[4] = {0x00, 0x00, 0x00, 0x01};

。。。。。。。。。。。。。。。。。

。。。。。。。。。。。。。。。。。。。。

。。。。。。。。。。。。。。。。。。。。。。
  //為儲存Buff的緩衝區,在這個地方將Buff呼叫給FFMPEG

 int imageWidth=0;
 int imageHeight=0;
 if (H264Status==H264STATUS_IFRAME ||H264Status==H264STATUS_PFRAME)
 {

//封裝H264解碼函式;
  bool bRet=H264DecodeClass.H264DecodeProcess((unsigned char*)pH264ReceiveBuff,frameSize,(unsigned char *)DecodeBuff,imageWidth,imageHeight);

  if (bRet&&imageWidth>0&&imageHeight>0)
  {
   TRACE("receive a frame,frameSize=%d\n",frameSize);

//這裡呼叫DDRAW顯示影象;

。。。。。。。。。。。。。。。。。。。。。。。。。

。。。。。。。。。。。。。。。。。。。。。。。。。。


    }
 
 }

 // Then continue, to request the next frame of data:
 continuePlaying();
}

3)ddraw yuv420p直接顯示;首先建立2個表面,主表面和離屏表面;將yuv420p的資料copy到離屏表面,然後blt到主表面進行繪製;這個在我的部落格裡面也有講到,有需要的朋友可以參考前面的ddraw yuv視訊顯示的文章;

大家可以參考我的思路自己實現H264接收,解碼,顯示功能;