Custom buffer problem

Examples and samples for those who develop software with FFmpeg.
Post Reply
naruto
Posts: 1
Joined: Wed Dec 02, 2015 8:48 am

Custom buffer problem

Post by naruto » Wed Dec 02, 2015 9:06 am

Hello everyone, new guy here. I have a question regarding buffer read with ffmpeg.
Idea is as it follows: an outside module (can not change it) is providing me video stream in chunks of data and it is giving me input data and it's size in bytes. I have to put it to a buffer and read it with ffmpeg and extract video frames. Each time I receive new data, my function "framfunction" will be called. My current attempt is like this (I know it is messy. Any suggestions around ffmpeg code and buffer design are welcome). It is essentially based on https://www.ffmpeg.org/doxygen/2.2/avio ... ample.html and http://dranger.com/ffmpeg/tutorial01.html :

Code: Select all

#include <iostream>
#include <string>

extern "C"
{
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#include <libavformat/avio.h>
#include <libavutil/file.h>
}
struct buffer_data {
	uint8_t *ptr;
	size_t size; ///< size left in the buffer
};

static int read_packet(void *opaque, uint8_t *buf, int buf_size)
{
	struct buffer_data *bd = (struct buffer_data *)opaque;
	buf_size = FFMIN(buf_size, bd->size);
	/* copy internal buffer data to buf */
	memcpy(buf, bd->ptr, buf_size);
	bd->ptr += buf_size;
	bd->size -= buf_size;
	return buf_size;
}

class videoclass
{
private:
	uint8_t* inputdatabuffer;
	size_t offset;

public:
	videoclass();
	~videoclass();
	int framfunction(uint8_t* inputbytes, int inputbytessize);
};

videoclass::videoclass()
	: inputdatabuffer(nullptr)
	, offset(0)
{
	inputdatabuffer = new uint8_t[8 * 1024 * 1024];
}

videoclass::~videoclass()
{
	delete[] inputdatabuffer;
}


int videoclass::framfunction(uint8_t* inputbytes, int inputbytessize)
{
	int i, videoStream, numBytes, frameFinished;
	AVFormatContext *pFormatCtx = NULL;
	AVCodecContext *pCodecCtx = NULL;
	AVIOContext	*avio_ctx = NULL;
	AVCodec	*pCodec = NULL;
	AVFrame	*pFrame = NULL;
	AVFrame	*pFrameRGB = NULL;
	AVPacket packet;
	uint8_t	*buffer = NULL;
	uint8_t	*avio_ctx_buffer = NULL;
	size_t	avio_ctx_buffer_size = 4096;
	size_t	bytes_processed = 0;
	struct buffer_data bd = { 0 };
	
	//if (av_file_map("sample.ts", &inputbytes, &inputbytessize, 0, NULL) < 0)//
	//	return -1;

	memcpy(inputdatabuffer + offset, inputbytes, inputbytessize);//copy new data to buffer inputdatabuffer with offset calculated at the end of previous function run. 
	offset += inputbytessize; //total number of bytes in buffer. Size of an unprocessed data from the last run + size of new data (inputbytessize)

	bd.ptr = inputdatabuffer;
	bd.size = offset;

	if (!(pFormatCtx = avformat_alloc_context()))
		return -1;
	avio_ctx_buffer = (uint8_t *)av_malloc(avio_ctx_buffer_size);
	avio_ctx = avio_alloc_context(avio_ctx_buffer, avio_ctx_buffer_size,0, &bd, &read_packet, NULL, NULL);
	pFormatCtx->pb = avio_ctx;
	
	av_register_all(); 
	avcodec_register_all();

	pFrame = av_frame_alloc(); 
	pFrameRGB = av_frame_alloc(); 

	if (avformat_open_input(&pFormatCtx, NULL, NULL, NULL) != 0) 
		return -2;
	if (avformat_find_stream_info(pFormatCtx, NULL) < 0)
		return -3;

	videoStream = -1;
	for (i = 0; i < pFormatCtx->nb_streams; i++)
		if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { 
			videoStream = i;
			break;
		}
	if (videoStream == -1) 
		return -4;

	pCodecCtx = pFormatCtx->streams[videoStream]->codec; 

	pCodec = avcodec_find_decoder(pCodecCtx->codec_id); 
	if (pCodec == NULL){
		std::cout << "Unsupported codec" << std::endl;
		return -5;
	}

	if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
		return -6; 

	numBytes = avpicture_get_size(PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height); 
	buffer = (uint8_t *)av_malloc(numBytes*sizeof(uint8_t));

	avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height); 

	while (av_read_frame(pFormatCtx, &packet) >= 0){
		if (packet.stream_index == videoStream){ 
			avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet); 
			if (frameFinished){ 
				std::cout << "Yaay, frame found" << std::endl;
				}
				av_free_packet(&packet); 

				bytes_processed = (size_t)pFormatCtx->pb->pos; //data which is processed so far (x bytes out of inputbytessize)??????????????????????????????
	
		}

	}

	offset -= bytes_processed; //size of unprocessed data

	av_free(buffer);
	av_free(pFrameRGB);
	av_free(pFrame);

	avcodec_close(pCodecCtx);

	av_freep(&avio_ctx->buffer);
	av_freep(&avio_ctx);


	avformat_close_input(&pFormatCtx);

	
	memmove(inputdatabuffer, inputdatabuffer + bytes_processed, offset);//move unprocessed data to begining of the main buffer
	
		return 0;
}
Comments are pointing to my attempt to address this issue. It works - sort of. But I would like it to work properly.

Tnx

Post Reply