rendered paste bodyvoid
Decoder::SaveFrame(AVFrame *pFrame, int width, int height, int ct, KString outPath) {
FILE *pFile;
char szFilename[32];
outPath.append("/frame%04i.ppm"); //4-zero's padding
printf("Saving frame : ");
printf(outPath.c_str(), ct);
printf("\n");
sprintf(szFilename, outPath.c_str(), ct);
pFile=fopen(szFilename, "wb");
if(pFile == NULL)
{
return;
}
fprintf(pFile, "P6\n%d %d\n255\n", width, height);
for(int idx = 0 ; idx < height ; idx++)
fwrite(pFrame->data[0]+idx*pFrame->linesize[0], 1, width*3, pFile);
fclose(pFile);
}
int
Decoder::Decode(KString fileName, KString outPath, bool doSave, KString &errMsg)
{
AVFormatContext *pFormatCtx=NULL;
int videoStream;
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
AVFrame *pFrame;
AVFrame *pFrameRGB;
AVPacket packet;
int gotFrame;
int numBytes;
uint8_t *buffer;
struct SwsContext *img_convert_ctx;
int frameCount=0;
int streamHeight = 0;
int streamWidth = 0;
PixelFormat pixelFmt = PIX_FMT_NONE;
// Register all formats and codecs
av_register_all();
// Open video file
if(avformat_open_input(&pFormatCtx, fileName.c_str(), NULL, NULL)!=0)
{
errMsg = "Could not open file";
return -1;
}
/* fill the streams in the format context */
if(avformat_find_stream_info(pFormatCtx, NULL) < 0)
{
errMsg = "Could not stream packet information.";
return -1;
}
if(_debug)
av_dump_format(pFormatCtx, 0, _debugOutputFile.c_str(), 0);
/*
Look at ffprobe.c line.1575 for full way to assign decoder to each input stream.
This will only look for the video stream within the encoded file.
*/
videoStream = -1;
for(int i = 0 ; i < pFormatCtx->nb_streams ; i++)
{
if( pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO ) {
videoStream = i;
streamHeight = pFormatCtx->streams[i]->codec->height;
streamWidth = pFormatCtx->streams[i]->codec->width;
pixelFmt = pFormatCtx->streams[i]->codec->pix_fmt;
break;
}
}
if(videoStream== -1)
{
errMsg = "Unable to find video stream.";
return -1;
}
if(streamHeight == 0 || streamWidth == 0)
{
if(_suggestedWidth == 0 || _suggestedWidth == 0)
{
errMsg = "No dimensions provided in codec, suggest non-zero width and height.";
return -1;
}
streamHeight = _suggestedHeight;
streamWidth = _suggestedWidth;
}
if(pixelFmt == PIX_FMT_NONE)
{
if(_suggestedPixFmt == -1)
{
errMsg = "No pixel format provided in codec, suggest pixel format.";
return -1;
}
pixelFmt = (PixelFormat)_suggestedPixFmt;
}
pCodecCtx = pFormatCtx->streams[videoStream]->codec;
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if(pCodec == NULL)
{
errMsg = "Codec not supported.";
return -1;
}
pCodecCtx = avcodec_alloc_context3(pCodec);
pCodecCtx->width = streamWidth;
pCodecCtx->height = streamHeight;
pCodecCtx->pix_fmt = PIX_FMT_YUVJ420P;
if( avcodec_open(pCodecCtx, pCodec) < 0 )
{
errMsg = "Was unable to open codec.";
return -1;
}
// Allocate video frame
pFrame = avcodec_alloc_frame();
// Allocate an AVFrame structure
pFrameRGB = avcodec_alloc_frame();
if( pFrameRGB == NULL )
{
errMsg = "Failed to allocate frame.";
return -1;
}
numBytes = avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);
buffer = (uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
avpicture_fill( (AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height );
int w = pCodecCtx->width;
int h = pCodecCtx->height;
img_convert_ctx = sws_getContext
(
w,
h,
pCodecCtx->pix_fmt,
w,
h,
PIX_FMT_RGB24,
SWS_BICUBIC,
/* Optional filters */
NULL,
NULL,
NULL
);
int ct=0;
while(av_read_frame(pFormatCtx, &packet) >= 0)
{
// Is this a packet from the video stream?
if(packet.stream_index == videoStream)
{
/* Decode video returns gotFrame(3rd) flag if success */
int len = avcodec_decode_video2(pCodecCtx, pFrame, &gotFrame, &packet);
if ( len < 0 )
{
errMsg = "Error decoding frame.";
return 1;
}
if(gotFrame)
{
sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0,
pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
if(doSave)
SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, (frameCount + 1), outPath);
frameCount++;
}
}
/* Free the packet that was allocated by av_read_frame */
av_free_packet(&packet);
} //End while
/* some codecs, such as MPEG, transmit the I and P frame with a
latency of one frame. You must do the following to have a
chance to get the last frame of the video */
packet.data = NULL;
packet.size = 0;
gotFrame = -1;
int len = avcodec_decode_video2(pCodecCtx, pFrame, &gotFrame, &packet);
if (gotFrame) {
sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0,
pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
if(doSave)
SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, ++frameCount, outPath);
av_free_packet(&packet);
}
av_free(buffer);
av_free(pFrameRGB);
av_free(pFrame);
avcodec_close(pCodecCtx);
av_close_input_file(pFormatCtx);
}