All pastes #2120920 Raw Edit

Something

public text v1 · immutable
#2120920 ·published 2012-02-23 00:12 UTC
rendered paste body
void 
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);
}