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接收,解碼,顯示功能;