Hello, Please see attached files to see how you can use FFmpeg's libavformat library to write a framer for H264 video. The code has been tested with .mp4 files, and with a tweak or two, will work for any other container format. It assumes that the nal_length_size is 4, but one can change this so that the nal_length_size is dynamically derived from what libavformat knows it is. One nice thing about libavformat is that it will parse the video stream for you and always give you a full video frame on av_read_frame. (An access unit).
Regards, -- B. Gitonga Marete Tel: +254-722-151-590
#include "LavfH264StreamFramer.hh" extern "C" { #include <libavcodec/avcodec.h> } extern "C" { #include <libavutil/rational.h> } const int microInSec = 1000000; LavfH264StreamFramer::LavfH264StreamFramer(UsageEnvironment& env, AVFormatContext* pfmtContext, char* sourceFile, int streamIndex) : H264VideoStreamFramer(env, NULL) { fpFmtContext = pfmtContext; fSourceFile = sourceFile; fStreamIndex = streamIndex; } LavfH264StreamFramer::~LavfH264StreamFramer() { av_close_input_file(fpFmtContext); } LavfH264StreamFramer* LavfH264StreamFramer::createNew(UsageEnvironment& env, char *sourceFile) { AVFormatContext* pFmtContext; // Important: Register all codecs and formats av_register_all(); if(av_open_input_file(&pFmtContext, sourceFile, NULL, 0, NULL) != 0){ fprintf(stderr, "LavfH264StreamFramer:createNew(): Could not open " "source file %s\n", sourceFile); return NULL; } if(av_find_stream_info(pFmtContext) < 0){ fprintf(stderr, "LavfH264StreamFramer:createNew(): Could not find " "stream information for source file %s\n", sourceFile); return NULL; } // In the following, we choose the first H.264 stream in the file int streamIndex = -1; for(unsigned int i = 0; i < pFmtContext->nb_streams; i++){ if(pFmtContext->streams[i]->codec->codec_id == CODEC_ID_H264){ streamIndex = i; break; } } if(streamIndex == -1){ fprintf(stderr, "LavfH264StreamFramer:createNew(): Could not find " "a H.264 video stream in source file %s\n", sourceFile); return NULL; } return new LavfH264StreamFramer(env, pFmtContext, sourceFile, streamIndex); } Boolean LavfH264StreamFramer::currentNALUnitEndsAccessUnit() { return True; } void LavfH264StreamFramer::doGetNextFrame() { AVPacket packet; //fprintf(stderr, "doGetNextFrame() called\n"); while(1){ if(av_read_frame(fpFmtContext, &packet) != 0){ handleClosure(this); /* XXX Should we call av_free_packet() here? */ return; } if(packet.stream_index == fStreamIndex){ break; } else{ av_free_packet(&packet); } } // Successfully read a packet of required type // Set the frame size fFrameSize = packet.size - 4; //fprintf(stderr, "Frame Size: %u", fFrameSize); if(fFrameSize <= fMaxSize){ memcpy(fTo, packet.data + 4, fFrameSize); fNumTruncatedBytes = 0; } else{ memcpy(fTo, packet.data + 4 , fMaxSize); fNumTruncatedBytes = fFrameSize - fMaxSize; } /* Calculate fPresentationTime and fDurationInMicroseconds */ int timeBaseNum = fpFmtContext->streams[fStreamIndex]->r_frame_rate.den; int timeBaseDen = fpFmtContext->streams[fStreamIndex]->r_frame_rate.num; double timeUnitSecs = timeBaseNum / (double) timeBaseDen; fDurationInMicroseconds = ((packet.duration) * timeUnitSecs) * microInSec; //fprintf(stderr, " timeBaseNum %d", timeBaseNum); //fprintf(stderr, " timeBaseDen %d", timeBaseDen); //fprintf(stderr, " Duration %u\n", fDurationInMicroseconds); /* When not decompressing frames, libavformat recommends to use dts* * since some sources contain B frames */ int ptsMicroseconds = ((packet.pts) * timeUnitSecs) * microInSec; fPresentationTime.tv_sec = ptsMicroseconds / microInSec; fPresentationTime.tv_usec = ptsMicroseconds % microInSec; //We are done with the packet for now av_free_packet(&packet); afterGetting(this); }
#ifndef _LAVF_H264_STREAM_FRAMER_HH #define _LAVF_H264_STREAM_FRAMER_HH #include "H264VideoStreamFramer.hh" #ifdef __cplusplus extern "C" { #endif #include <libavformat/avformat.h> #ifdef __cplusplus } #endif class LavfH264StreamFramer : public H264VideoStreamFramer { public: static LavfH264StreamFramer* createNew(UsageEnvironment& env, char* sourceFile); virtual Boolean currentNALUnitEndsAccessUnit(); virtual void doGetNextFrame(); protected: LavfH264StreamFramer(UsageEnvironment& env, AVFormatContext *pfmtContext, char* sourceFile, int streamIndex); virtual ~LavfH264StreamFramer(); private: AVFormatContext* fpFmtContext; char* fSourceFile; int fStreamIndex; }; #endif // _LAVF_H264_STREAM_FRAMER_HH
_______________________________________________ live-devel mailing list live-devel@lists.live555.com http://lists.live555.com/mailman/listinfo/live-devel