I have a source code in C++ using libavcodec for decoding h264 rtsp stream frames. This source code was written using ffmpeg 1.1. Now when I upgraded to ffmpeg 3.3, all things seem to work correctly except that decoding frames not work.
In old version, I was using avcodec_decode_video2. After upgrading, avcodec_decode_video2 always sets got_picture to 0 and return value is equal to the size of the input packet (which means all data is used). And never a frame is decoded.
I have also removed avcodec_decode_video2 and done decoding with avcodec_send_packet and avcodec_receive_frame, but avcodec_send_packet always returns 0 and avcodec_receive_frame always returns -11 (EAGAIN).
This is the code I use for decoding:
#include "stdafx.h"
#include <stdlib.h>
#include <string>
#include <iostream>
using namespace std;
extern "C"{
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"
#include "libavutil/pixfmt.h"
}
int extraDataSize;
static const int MaxExtraDataSize = 1024;
uint8_t extraDataBuffer[MaxExtraDataSize];
void AddExtraData(uint8_t* data, int size)
{
auto newSize = extraDataSize + size;
if (newSize > MaxExtraDataSize){
throw "extradata exceeds size limit";
}
memcpy(extraDataBuffer + extraDataSize, data, size);
extraDataSize = newSize;
}
int _tmain(int argc, _TCHAR* argv[])
{
std::string strFramesPath("g:\\frames\\");
AVCodec* avCodec;
AVCodecContext* avCodecContext;
AVFrame* avFrame;
AVCodecID codecId = AV_CODEC_ID_H264;
unsigned char sprops_part_1[9] = { 0x27, 0x42, 0x80, 0x1f, 0xda, 0x02, 0xd0, 0x49, 0x10 };
unsigned char sprops_part_2[4] = { 0x28, 0xce, 0x3c, 0x80 };
av_register_all();
avcodec_register_all();
avCodec = avcodec_find_decoder(codecId);
avCodecContext = avcodec_alloc_context3(avCodec);
if (!avCodecContext)
{
cout << "avcodec_alloc_context3 failed." << endl;
return 0;
}
uint8_t startCode[] = { 0x00, 0x00, 0x01 };
// sprops
{
// sprops 1
AddExtraData(startCode, sizeof(startCode));
AddExtraData(sprops_part_1, 9);
// sprops 2
AddExtraData(startCode, sizeof(startCode));
AddExtraData(sprops_part_2, 4);
avCodecContext->extradata = extraDataBuffer;
avCodecContext->extradata_size = extraDataSize;
}
AddExtraData(startCode, sizeof(startCode));
avCodecContext->flags = 0;
if (avcodec_open2(avCodecContext, avCodec, NULL) < 0)
{
cout << "failed to open codec" << endl;
return 0;
}
avFrame = av_frame_alloc();
if (!avFrame)
{
cout << "failed to alloc frame" << endl;
return 0;
}
void *buffer = malloc(100 * 1024); // 100 KB buffer - all frames fit in this buffer
for (int nFrameIndex = 0; nFrameIndex < 257; nFrameIndex++)
{
std::string strFilename = std::string("g:\\frames\\" + std::to_string(nFrameIndex));
FILE* f = fopen(strFilename.c_str(), "rb");
fseek(f, 0, SEEK_END);
long nFileSize = ftell(f);
fseek(f, 0, SEEK_SET);
size_t nReadSize = fread(buffer, 1, nFileSize, f);
// cout << strFilename << endl;
if (nReadSize != nFileSize)
{
cout << "Error reading file data" << endl;
continue;
}
AVPacket avpkt;
avpkt.data = (uint8_t*)buffer;
avpkt.size = nReadSize;
while (avpkt.size > 0)
{
int got_frame = 0;
auto len = avcodec_decode_video2(avCodecContext, avFrame, &got_frame, &avpkt);
if (len < 0) {
//TODO: log error
cout << "Error decoding - error code: " << len << endl;
break;
}
if (got_frame)
{
cout << "* Got 1 Decoded Frame" << endl;
}
avpkt.size -= len;
avpkt.data += len;
}
}
getchar();
return 0;
}
Test frames data can be downloaded from this link:
Frames.zip (~3.7MB)
I have used windows builds from Builds - Zeranoe FFmpeg
If you copy paste this code into your IDE, the code compiles successfully. Using libavcodec new versions, no frame is decoded. Using old version of libavcodec (20141216-git-92a596f), decoding starts when feed frame 2.
Any ideas?
FFmpeg/libAV description is quite complex and probably not the best one in terms of understandability (if not to say it's bad). You should read it carefully.
However, what you are missing is to init the AVPacket by using av_init_packet. Or use av_packet_alloc() to create the packet which will initialize the packet (and is better for duplicating it later for encoding).
// code ...
AVPacket avpkt;
av_init_packet(&avpkt); // initialize packet
avpkt.data = (uint8_t*)buffer;
avpkt.size = nReadSize;
// code ...
or
// code ...
AVPacket* avpkt = av_packet_alloc();
avpkt->data = (uint8_t*)buffer;
avpkt->size = nReadSize;
// use ...
auto len = avcodec_decode_video2(avCodecContext, avFrame, &got_frame, avpkt);
Using av_packet_alloc() is also more consistent within the code since you also use AVFrame as a pointer.
Remember to free the packets/frames/pictures as well, otherwise you will have memory leaks.
Also here is a (more or less) good/"up-to-date" tutorial for ffmpeg.
Related
I writting a software for my classes that receive a h264 stream from a drone and i need to convert the video stream to opencv Mat.
I have no trouble to receive the frame and if i save it to a .264 file i can read the output with VLC.
The drone is sending IDR-Frame and P-Frame , since i don't need to see the video stream juste some frame of it, i was thinking of only using the IDR-Frame to get the image but i have trouble to understand how to use libavcodec from FFMPEG, how can i create a AVFrame from my IDR-Frame and how to convert it to cv::Mat after.
i have try the following code, i have store the full frame in .raw file and i try to decode them , but i get read error when i try to parse the packet to a frame, i don't thing a initialize the buffer of ARPacket the right way :
AVFormatContext* fc = 0;
int vi = -1; // vi veut dire video index
inline cv::Mat avframe_to_mat(const AVFrame* avframe)
{
AVFrame dst;
cv::Mat m;
memset(&dst, 0, sizeof(dst));
int w = avframe->width, h = avframe->height;
m = cv::Mat(h, w, CV_8UC3);
dst.data[0] = (uint8_t*)m.data;
avpicture_fill((AVPicture*)&dst, dst.data[0], AV_PIX_FMT_BGR24, w, h);
struct SwsContext *convert_ctx = NULL;
enum AVPixelFormat src_pixfmt = AV_PIX_FMT_BGR24;
enum AVPixelFormat dst_pixfmt = AV_PIX_FMT_BGR24;
convert_ctx = sws_getContext(w, h, src_pixfmt, w, h, dst_pixfmt, SWS_FAST_BILINEAR, NULL, NULL, NULL);
sws_scale(convert_ctx, avframe->data, avframe->linesize, 0, h, dst.data, dst.linesize);
sws_freeContext(convert_ctx);
return m;
}
inline bool init_stream(unsigned char* data, int len)
{
const char* file = "test.avi";
const AVCodecID codec_id = AV_CODEC_ID_H264;
AVCodec* codec = avcodec_find_encoder(codec_id);
// Crée le container pour le stream
fc = avformat_alloc_context();
/*
AVOutputFormat *of = av_guess_format(0, file, 0);
fc = avformat_alloc_context();
fc->oformat = of;
strcpy(fc->filename, file);
*/
int br = 1000000;
int w = 640;
int h = 360;
int fps = 24;
// ajoute un stream video
AVStream* pst = avformat_new_stream(fc, codec); // Pourquoi je passe pas le codec ici ?
vi = pst->index;
codec_context = avcodec_alloc_context3(codec);
codec_context->bit_rate = br;
codec_context->width = w;
codec_context->height = h;
codec_context->time_base = {1,fps};
codec_context->gop_size = 10; // Emit one intra frame every ten frames
codec_context->max_b_frames = 1;
codec_context->pix_fmt = AV_PIX_FMT_YUV420P;
// Vu quon n'est en h264
av_opt_set(codec_context->priv_data, "preset", "slow", 0);
// Ouvre notre codec
if(avcodec_open2(codec_context, codec,nullptr) < 0)
{
cerr << "Impossible d'ouvrir le codec" << endl;
return false;
}
if (!(fc->oformat->flags & AVFMT_NOFILE))
avio_open(&fc->pb, fc->filename,0);
// avformat_write_header(fc,nullptr);
return true;
}
inline void append_stream(uint8_t* data, int len)
{
if( 0 > vi)
{
cerr << "video index is less than 0" << endl;
return;
}
AVStream* pst = fc->streams[vi];
AVPacket pkt;
// Init un nouveau packet
av_init_packet(&pkt);
pkt.flags |= AV_PKT_FLAG_KEY;
pkt.data = data;
pkt.stream_index = pst->index;
pkt.size = len;
pkt.dts = AV_NOPTS_VALUE;
pkt.pts = AV_NOPTS_VALUE;
// ERROR accessing location
av_interleaved_write_frame(fc, &pkt);
}
inline void execute_staging_test(const fs::path& folder, int nbr_trame)
{
fs::path file_name = folder / "stream.bin";
if(!fs::exists(file_name))
{
cerr << "The file " << file_name.string() << " does not exists" << endl;
return;
}
avcodec_register_all();
av_log_set_level(AV_LOG_DEBUG);
int length = 0;
char* buffer;
for(int i = 0; i < nbr_trame;i++)
{
fs::path file = std::to_string(i) + ".raw";
file = folder / file;
cout << "Got frame on " << file.string() << endl;
ifstream ifs(file, ofstream::binary);
// Get la longeur du fichier pour savoir le buffer a prendre
ifs.seekg(0, ios::end);
length = ifs.tellg();
ifs.seekg(0, ios::beg);
if (length == 0) {
std::cerr << "No data in file " << file << std::endl;
return;
}
buffer = new char[length];
std::cout << "File " << file << " length is " << length << std::endl;
ifs.read(buffer, length);
cv::VideoWriter vw;
int codec = cv::VideoWriter::fourcc('X', '2', '6', '4');
if(!fc)
{
if(!init_stream((unsigned char*)buffer, length))
{
return;
}
}
if(fc)
{
append_stream((unsigned char*)buffer, length);
}
}
}
Thanks you very mutch if you can help me , i'm a novice in c++ and i have never deal with video stream. If you want to see the full code its host on github repo to this project
One of the things I'm trying to achieve is parallel encoding via FFmpeg's c API. This looks to work out of the box quite nicely; however, I've changed the goal posts slightly:
In an existing application, I already have a thread pool at hand. Instead of using another thread pool via FFmpeg, I would like reuse the existing thread pool in my application. Having studied the latest FFmpeg trunk docs, it very much looks possible.
Using some FFmpeg sample code, I've created a sample application to demonstrate what I'm trying to achieve (see below). The sample app generates a video-only mpeg2 ts using the mp2v codec.
The problem I'm experiencing is that the custom 'thread_execute' or 'thread_execute2' are never invoked. This is despite the fact that the codec appears to indicate that threading is supported. Please be aware that I have not yet plumbed in the thread pool just yet. My first goal is for it to call the custom function pointer.
I've tried to get assistance on the FFmpeg mailing lists but to no avail.
#include <iostream>
#include <thread>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <cstring>
#include <future>
extern "C"
{
#include <libavutil/avassert.h>
#include <libavutil/channel_layout.h>
#include <libavutil/opt.h>
#include <libavutil/timestamp.h>
#include <libavformat/avformat.h>
//#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
}
#define STREAM_DURATION 1000.0
#define STREAM_FRAME_RATE 25 /* 25 images/s */
#define STREAM_PIX_FMT AV_PIX_FMT_YUV420P /* default pix_fmt */
#define SCALE_FLAGS SWS_BICUBIC
// a wrapper around a single output AVStream
typedef struct OutputStream {
AVStream *st;
AVCodecContext *enc;
/* pts of the next frame that will be generated */
int64_t next_pts;
int samples_count;
AVFrame *frame;
AVFrame *tmp_frame;
float t, tincr, tincr2;
struct SwsContext *sws_ctx;
struct SwrContext *swr_ctx;
} OutputStream;
/////////////////////////////////////////////////////////////////////////////
// The ffmpeg variation raises compiler warnings.
char *cb_av_ts2str(char *buf, int64_t ts)
{
std::memset(buf,0,AV_TS_MAX_STRING_SIZE);
return av_ts_make_string(buf,ts);
}
/////////////////////////////////////////////////////////////////////////////
// The ffmpeg variation raises compiler warnings.
char *cb_av_ts2timestr(char *buf, int64_t ts, AVRational *tb)
{
std::memset(buf,0,sizeof(AV_TS_MAX_STRING_SIZE));
return av_ts_make_time_string(buf,ts,tb);
}
/////////////////////////////////////////////////////////////////////////////
// The ffmpeg variation raises compiler warnings.
char *cb_av_err2str(char *errbuf, size_t errbuf_size, int errnum)
{
std::memset(errbuf,0,errbuf_size);
return av_make_error_string(errbuf,errbuf_size,errnum);
}
int thread_execute(AVCodecContext* s, int (*func)(AVCodecContext *c2, void *arg2), void* arg, int* ret, int count, int size)
{
// Do it all serially for now
std::cout << "thread_execute" << std::endl;
for (int k = 0; k < count; ++k)
{
ret[k] = func(s, arg);
}
return 0;
}
int thread_execute2(AVCodecContext* s, int (*func)(AVCodecContext* c2, void* arg2, int, int), void* arg, int* ret, int count)
{
// Do it all serially for now
std::cout << "thread_execute2" << std::endl;
for (int k = 0; k < count; ++k)
{
ret[k] = func(s, arg, k, count);
}
return 0;
}
static void log_packet(const AVFormatContext *fmt_ctx, const AVPacket *pkt)
{
char s[AV_TS_MAX_STRING_SIZE];
AVRational *time_base = &fmt_ctx->streams[pkt->stream_index]->time_base;
printf("pts:%s pts_time:%s dts:%s dts_time:%s duration:%s duration_time:%s stream_index:%d\n",
cb_av_ts2str(s,pkt->pts), cb_av_ts2timestr(s,pkt->pts, time_base),
cb_av_ts2str(s,pkt->dts), cb_av_ts2timestr(s,pkt->dts, time_base),
cb_av_ts2str(s,pkt->duration), cb_av_ts2timestr(s,pkt->duration, time_base),
pkt->stream_index);
}
static int write_frame(AVFormatContext *fmt_ctx, const AVRational *time_base, AVStream *st, AVPacket *pkt)
{
/* rescale output packet timestamp values from codec to stream timebase */
av_packet_rescale_ts(pkt, *time_base, st->time_base);
pkt->stream_index = st->index;
/* Write the compressed frame to the media file. */
log_packet(fmt_ctx, pkt);
return av_interleaved_write_frame(fmt_ctx, pkt);
}
/* Add an output stream. */
static void add_stream(OutputStream *ost, AVFormatContext *oc,
AVCodec **codec,
enum AVCodecID codec_id)
{
AVCodecContext *c;
int i;
/* find the encoder */
*codec = avcodec_find_encoder(codec_id);
if (!(*codec)) {
fprintf(stderr, "Could not find encoder for '%s'\n",
avcodec_get_name(codec_id));
exit(1);
}
ost->st = avformat_new_stream(oc, NULL);
if (!ost->st) {
fprintf(stderr, "Could not allocate stream\n");
exit(1);
}
ost->st->id = oc->nb_streams-1;
c = avcodec_alloc_context3(*codec);
if (!c) {
fprintf(stderr, "Could not alloc an encoding context\n");
exit(1);
}
ost->enc = c;
switch ((*codec)->type)
{
case AVMEDIA_TYPE_AUDIO:
c->sample_fmt = (*codec)->sample_fmts ?
(*codec)->sample_fmts[0] : AV_SAMPLE_FMT_FLTP;
c->bit_rate = 64000;
c->sample_rate = 44100;
if ((*codec)->supported_samplerates) {
c->sample_rate = (*codec)->supported_samplerates[0];
for (i = 0; (*codec)->supported_samplerates[i]; i++) {
if ((*codec)->supported_samplerates[i] == 44100)
c->sample_rate = 44100;
}
}
c->channels = av_get_channel_layout_nb_channels(c->channel_layout);
c->channel_layout = AV_CH_LAYOUT_STEREO;
if ((*codec)->channel_layouts) {
c->channel_layout = (*codec)->channel_layouts[0];
for (i = 0; (*codec)->channel_layouts[i]; i++) {
if ((*codec)->channel_layouts[i] == AV_CH_LAYOUT_STEREO)
c->channel_layout = AV_CH_LAYOUT_STEREO;
}
}
c->channels = av_get_channel_layout_nb_channels(c->channel_layout);
ost->st->time_base = (AVRational){ 1, c->sample_rate };
break;
case AVMEDIA_TYPE_VIDEO:
c->codec_id = codec_id;
c->bit_rate = 400000;
/* Resolution must be a multiple of two. */
c->width = 352;
c->height = 288;
/* timebase: This is the fundamental unit of time (in seconds) in terms
* of which frame timestamps are represented. For fixed-fps content,
* timebase should be 1/framerate and timestamp increments should be
* identical to 1. */
ost->st->time_base = (AVRational){ 1, STREAM_FRAME_RATE };
c->time_base = ost->st->time_base;
c->gop_size = 12; /* emit one intra frame every twelve frames at most */
c->pix_fmt = STREAM_PIX_FMT;
if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
/* just for testing, we also add B-frames */
c->max_b_frames = 2;
}
if (c->codec_id == AV_CODEC_ID_MPEG1VIDEO) {
/* Needed to avoid using macroblocks in which some coeffs overflow.
* This does not happen with normal video, it just happens here as
* the motion of the chroma plane does not match the luma plane. */
c->mb_decision = 2;
}
break;
default:
break;
}
if (c->codec->capabilities & AV_CODEC_CAP_FRAME_THREADS ||
c->codec->capabilities & AV_CODEC_CAP_SLICE_THREADS)
{
if (c->codec->capabilities & AV_CODEC_CAP_FRAME_THREADS)
{
c->thread_type = FF_THREAD_FRAME;
}
if (c->codec->capabilities & AV_CODEC_CAP_SLICE_THREADS)
{
c->thread_type = FF_THREAD_SLICE;
}
c->execute = &thread_execute;
c->execute2 = &thread_execute2;
c->thread_count = 4;
// NOTE: Testing opaque.
c->opaque = (void*)0xff;
}
/* Some formats want stream headers to be separate. */
if (oc->oformat->flags & AVFMT_GLOBALHEADER)
c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
/**************************************************************/
/* video output */
static AVFrame *alloc_picture(enum AVPixelFormat pix_fmt, int width, int height)
{
AVFrame *picture;
int ret;
picture = av_frame_alloc();
if (!picture)
return NULL;
picture->format = pix_fmt;
picture->width = width;
picture->height = height;
/* allocate the buffers for the frame data */
ret = av_frame_get_buffer(picture, 32);
if (ret < 0) {
fprintf(stderr, "Could not allocate frame data.\n");
exit(1);
}
return picture;
}
static void open_video(AVFormatContext *oc, AVCodec *codec, OutputStream *ost, AVDictionary *opt_arg)
{
int ret;
AVCodecContext *c = ost->enc;
//AVDictionary *opt = NULL;
//av_dict_copy(&opt, opt_arg, 0);
/* open the codec */
ret = avcodec_open2(c, codec, NULL);
//av_dict_free(&opt);
if (ret < 0) {
char s[AV_ERROR_MAX_STRING_SIZE];
fprintf(stderr, "Could not open video codec: %s\n", cb_av_err2str(s,AV_ERROR_MAX_STRING_SIZE,ret));
exit(1);
}
/* allocate and init a re-usable frame */
ost->frame = alloc_picture(c->pix_fmt, c->width, c->height);
if (!ost->frame) {
fprintf(stderr, "Could not allocate video frame\n");
exit(1);
}
/* If the output format is not YUV420P, then a temporary YUV420P
* picture is needed too. It is then converted to the required
* output format. */
ost->tmp_frame = NULL;
if (c->pix_fmt != AV_PIX_FMT_YUV420P) {
ost->tmp_frame = alloc_picture(AV_PIX_FMT_YUV420P, c->width, c->height);
if (!ost->tmp_frame) {
fprintf(stderr, "Could not allocate temporary picture\n");
exit(1);
}
}
/* copy the stream parameters to the muxer */
ret = avcodec_parameters_from_context(ost->st->codecpar, c);
if (ret < 0) {
fprintf(stderr, "Could not copy the stream parameters\n");
exit(1);
}
}
/* Prepare a dummy image. */
static void fill_yuv_image(AVFrame *pict, int frame_index,
int width, int height)
{
int x, y, i;
i = frame_index;
/* Y */
for (y = 0; y < height; y++)
for (x = 0; x < width; x++)
pict->data[0][y * pict->linesize[0] + x] = x + y + i * 3;
/* Cb and Cr */
for (y = 0; y < height / 2; y++) {
for (x = 0; x < width / 2; x++) {
pict->data[1][y * pict->linesize[1] + x] = 128 + y + i * 2;
pict->data[2][y * pict->linesize[2] + x] = 64 + x + i * 5;
}
}
}
static AVFrame *get_video_frame(OutputStream *ost)
{
AVCodecContext *c = ost->enc;
/* check if we want to generate more frames */
if (av_compare_ts(ost->next_pts, c->time_base,
STREAM_DURATION, (AVRational){ 1, 1 }) >= 0)
return NULL;
/* when we pass a frame to the encoder, it may keep a reference to it
* internally; make sure we do not overwrite it here */
if (av_frame_make_writable(ost->frame) < 0)
exit(1);
if (c->pix_fmt != AV_PIX_FMT_YUV420P) {
/* as we only generate a YUV420P picture, we must convert it
* to the codec pixel format if needed */
/*if (!ost->sws_ctx) {
ost->sws_ctx = sws_getContext(c->width, c->height,
AV_PIX_FMT_YUV420P,
c->width, c->height,
c->pix_fmt,
SCALE_FLAGS, NULL, NULL, NULL);
if (!ost->sws_ctx) {
fprintf(stderr,
"Could not initialize the conversion context\n");
exit(1);
}
}
fill_yuv_image(ost->tmp_frame, ost->next_pts, c->width, c->height);
sws_scale(ost->sws_ctx,
(const uint8_t * const *)ost->tmp_frame->data, ost->tmp_frame->linesize,
0, c->height, ost->frame->data, ost->frame->linesize);*/
} else {
fill_yuv_image(ost->frame, ost->next_pts, c->width, c->height);
}
ost->frame->pts = ost->next_pts++;
return ost->frame;
}
/*
* encode one video frame and send it to the muxer
* return 1 when encoding is finished, 0 otherwise
*/
static int write_video_frame(AVFormatContext *oc, OutputStream *ost)
{
int ret;
AVCodecContext *c;
AVFrame *frame;
int got_packet = 0;
AVPacket pkt = { 0 };
c = ost->enc;
frame = get_video_frame(ost);
if (frame)
{
ret = avcodec_send_frame(ost->enc, frame);
if (ret < 0)
{
char s[AV_ERROR_MAX_STRING_SIZE];
fprintf(stderr, "Error encoding video frame: %s\n", cb_av_err2str(s, AV_ERROR_MAX_STRING_SIZE, ret));
exit(1);
}
}
av_init_packet(&pkt);
ret = avcodec_receive_packet(ost->enc,&pkt);
if (ret < 0)
{
if (ret == AVERROR(EAGAIN)) { ret = 0; }
else
{
char s[AV_ERROR_MAX_STRING_SIZE];
fprintf(stderr, "Error receiving packet: %s\n", cb_av_err2str(s,AV_ERROR_MAX_STRING_SIZE,ret));
exit(1);
}
}
else
{
got_packet = 1;
ret = write_frame(oc, &c->time_base, ost->st, &pkt);
}
if (ret < 0) {
char s[AV_ERROR_MAX_STRING_SIZE];
fprintf(stderr, "Error while writing video frame: %s\n", cb_av_err2str(s,AV_ERROR_MAX_STRING_SIZE,ret));
exit(1);
}
return (frame || got_packet) ? 0 : 1;
}
static void close_stream(AVFormatContext *oc, OutputStream *ost)
{
avcodec_free_context(&ost->enc);
av_frame_free(&ost->frame);
av_frame_free(&ost->tmp_frame);
//sws_freeContext(ost->sws_ctx);
//swr_free(&ost->swr_ctx);
}
/**************************************************************/
/* media file output */
int main(int argc, char **argv)
{
OutputStream video_st = { 0 }, audio_st = { 0 };
const char *filename;
AVOutputFormat *fmt;
AVFormatContext *oc;
AVCodec /**audio_codec,*/ *video_codec;
int ret;
int have_video = 0, have_audio = 0;
int encode_video = 0, encode_audio = 0;
AVDictionary *opt = NULL;
int i;
/* Initialize libavcodec, and register all codecs and formats. */
av_register_all();
avformat_network_init();
if (argc < 2) {
printf("usage: %s output_file\n"
"API example program to output a media file with libavformat.\n"
"This program generates a synthetic audio and video stream, encodes and\n"
"muxes them into a file named output_file.\n"
"The output format is automatically guessed according to the file extension.\n"
"Raw images can also be output by using '%%d' in the filename.\n"
"\n", argv[0]);
return 1;
}
filename = argv[1];
for (i = 2; i+1 < argc; i+=2) {
if (!strcmp(argv[i], "-flags") || !strcmp(argv[i], "-fflags"))
av_dict_set(&opt, argv[i]+1, argv[i+1], 0);
}
const char *pfilename = filename;
/* allocate the output media context */
avformat_alloc_output_context2(&oc, NULL, "mpegts", pfilename);
if (!oc) {
printf("Could not deduce output format from file extension: using MPEG.\n");
avformat_alloc_output_context2(&oc, NULL, "mpeg", pfilename);
}
if (!oc)
return 1;
fmt = oc->oformat;
/* Add the audio and video streams using the default format codecs
* and initialize the codecs. */
if (fmt->video_codec != AV_CODEC_ID_NONE) {
add_stream(&video_st, oc, &video_codec, fmt->video_codec);
have_video = 1;
encode_video = 1;
}
/*if (fmt->audio_codec != AV_CODEC_ID_NONE) {
add_stream(&audio_st, oc, &audio_codec, fmt->audio_codec);
have_audio = 1;
encode_audio = 1;
}*/
/* Now that all the parameters are set, we can open the audio and
* video codecs and allocate the necessary encode buffers. */
if (have_video)
open_video(oc, video_codec, &video_st, opt);
//if (have_audio)
// open_audio(oc, audio_codec, &audio_st, opt);
av_dump_format(oc, 0, pfilename, 1);
/* open the output file, if needed */
if (!(fmt->flags & AVFMT_NOFILE)) {
ret = avio_open(&oc->pb, pfilename, AVIO_FLAG_WRITE);
if (ret < 0) {
char s[AV_ERROR_MAX_STRING_SIZE];
fprintf(stderr, "Could not open '%s': %s\n", pfilename,
cb_av_err2str(s,AV_ERROR_MAX_STRING_SIZE,ret));
return 1;
}
}
/* Write the stream header, if any. */
ret = avformat_write_header(oc, &opt);
if (ret < 0) {
char s[AV_ERROR_MAX_STRING_SIZE];
fprintf(stderr, "Error occurred when opening output file: %s\n",
cb_av_err2str(s,AV_ERROR_MAX_STRING_SIZE,ret));
return 1;
}
while (encode_video || encode_audio) {
/* select the stream to encode */
if (encode_video &&
(!encode_audio || av_compare_ts(video_st.next_pts, video_st.enc->time_base,
audio_st.next_pts, audio_st.enc->time_base) <= 0)) {
encode_video = !write_video_frame(oc, &video_st);
} else {
//encode_audio = !write_audio_frame(oc, &audio_st);
}
//std::this_thread::sleep_for(std::chrono::milliseconds(35));
}
/* Write the trailer, if any. The trailer must be written before you
* close the CodecContexts open when you wrote the header; otherwise
* av_write_trailer() may try to use memory that was freed on
* av_codec_close(). */
av_write_trailer(oc);
/* Close each codec. */
if (have_video)
close_stream(oc, &video_st);
if (have_audio)
close_stream(oc, &audio_st);
if (!(fmt->flags & AVFMT_NOFILE))
/* Close the output file. */
avio_closep(&oc->pb);
/* free the stream */
avformat_free_context(oc);
return 0;
}
//
Environment:
Ubuntu Zesty (17.04)
FFmpeg version 3.2.4 (via package manager)
gcc 6.3 (C++)
You have to do following:
call avcodec_alloc_context3(...). This call will set default execute and execute2 functions in new context
set c->thread_count = number_of_threads_in_your_thread_pool()
call avcodec_open2(...).
set c->execute and c->execute2 to point to your functions
call ff_thread_free(c). This function isnt exposed in libavcodec headers but you can add following line:
extern "C" void ff_thread_free(AVCodecContext *s);
Drawback is that libavcodec will create internal thread pool after avcodec_open2(...) call, and that pool will be deleted in ff_thread_free() call.
Internal thread pool is very efficient, but its not good if you plan to do parallel encoding of multiple video feeds. In that case libavcodec will create separate thread pool for each encoding video feed.
I am trying to compress and decompress raw PCM (16-Bit) audio, using OPUS.
Here below is my code for opus_encoder.c. If I remove my decoder.c, the buffer works just fine as in the microphone is able to take in raw PCM data. However, once I have implemented my decoder class, it gave me a lot of errors such as memory allocation, heap corruption and so on. Here are some of my errors:
std::bad_alloc at memory location 0x0031D4BC
Stack overflow (parameters: 0x00000000, 0x05122000)
Access violation reading location 0x04A40000.
Based on my understanding, I think my decoder size cannot allocate the memory properly. Can you take a look at my codes and see what went wrong?
Opus_encoder.c
#include "opusencoder.h"
#include <QtConcurrent/QtConcurrent>
opusencoder::opusencoder(){
}
opusencoder::~opusencoder(){
}
OpusEncoder *enc;
int error;
unsigned char *compressedbuffer;
opus_uint32 enc_final_range;
short pcm = 0;
unsigned char *opusencoder::encodedata(const char *audiodata, const unsigned int& size) {
if (size == 0)
return false;
enc = (OpusEncoder *)malloc(opus_encoder_get_size(1));
enc = opus_encoder_create(8000, 1, OPUS_APPLICATION_VOIP, &error);
if (enc == NULL)
{
exit;
}
opus_int32 rate;
opus_encoder_ctl(enc, OPUS_GET_BANDWIDTH(&rate));
this->encoded_data_size = rate;
int len;
for (int i = 0; i < size / 2; i++)
{
//combine pairs of bytes in the original data into two-byte number
//convert const char to short
pcm= audiodata[2 * i] << 8 | audiodata[(2 * i) + 1];
}
qDebug() << "audiodata: " << pcm << endl;
compressedbuffer = new (unsigned char[this->encoded_data_size]);
len = opus_encode(enc, &pcm, 320, compressedbuffer, this->encoded_data_size);
len = opus_packet_unpad(compressedbuffer, len);
len++;
if (len < 0)
{
qDebug() << "Failure to compress";
return NULL;
}
qDebug() << "COmpressed buffer:" << compressedbuffer << endl;
qDebug() << "opus_encode() ................................ OK.\n" << endl;
}
Opus_decoder.c
##include "opusdecoder.h"
#include <QtConcurrent/QtConcurrent>
#define OPUS_CLEAR(dst, n) (memset((dst), 0, (n)*sizeof(*(dst))))
int num_channels = 1;
opusdecoder::opusdecoder(){
}
opusdecoder::~opusdecoder(){
}
opus_int16* opusdecoder::decodedata(int frame_size, const unsigned char *data)
{
dec = opus_decoder_create(8000, 1, &err);
if (dec == NULL)
{
exit;
}
opus_int32 rate;
opus_decoder_ctl(dec, OPUS_GET_BANDWIDTH(&rate));
rate = decoded_data_size;
this->num_channels = num_channels;
int decodedatanotwo;
opus_int16 *decompress = new (opus_int16[frame_size * this->num_channels]);
opus_packet_get_nb_channels(data);
decodedatanotwo= opus_decode(dec, data, this->decoded_data_size, decompress, 320, 0);
if (decodedatanotwo < 0)
{
qDebug() << "Failure to decompress";
return NULL;
}
qDebug() << "opus_decode() ................................ OK.\n" << decodedatanotwo << endl;
if (decodedatanotwo != frame_size)
{
exit;
}
}
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 ("framfunction" function input parameters). I have to copy input data to a buffer and read it with ffmpeg (Zeranoe) and extract video frames. Each time I receive new data, my function "framfunction" will be called. All unprocessed data from a first run will be moved at the beginning of the buffer followed by a new data on the second run and so on. It is essentially based on source and Dranger tutorials. My current attempt is like this and just look at comments (I've left only ones regarding current buffer function) in code to get a picture what I want to do(I know it is messy and it works - sort of; skipping some frames. Any suggestions around ffmpeg code and buffer design are welcome):
#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;
};
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);
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[8388608]; //buffer where the input data will be stored
}
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. In other words - cope new data after unprocessed data from a previous call
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;
}
Call of my function would be something like this
WHILE(VIDEO_INPUT)
{
READ VIDEO DATA FROM INPUT BUFFER
STORE DATA FROM INPUT BUFFER AND SIZE OP THAT DATA TO VARIABLES NEW_DATA AND NEW_DATA_SIZE
CALL FUNCTION FRAMMUNCTION AND PASS NEW_DATA AND NEW_DATA_FUNCTION
DO OTHER THINGS
}
What I would like to know is what is exact size of unprocessed data. Comments in code are showing my attempt but I think it is not good enough so I need some help with that issue.
EDIT: magic question is how to get correct "bytes_processed" size. I've also made an pdf with explanation how my buffer should work pdf file
Thanks
I have started learning ffmpeg few weaks ago. At the moment I am able to transcode any video to mp4 using h264/AVC codec. The main scheme is something like that:
-open input
-demux
-decode
-encode
-mux
The actual code is below:
#include <iostream>
#include <math.h>
extern "C" {
#
ifndef __STDC_CONSTANT_MACROS# undef main /* Prevents SDL from overriding main() */ # define __STDC_CONSTANT_MACROS# endif
# pragma comment(lib, "avcodec.lib")# pragma comment(lib, "avformat.lib")# pragma comment(lib, "swscale.lib")# pragma comment(lib, "avutil.lib")
#include <libavcodec\avcodec.h>
#include <libavformat\avformat.h>
#include <libswscale\swscale.h>
#include <libavutil\mem.h>
#include <libavutil/opt.h>
#include <libavutil\channel_layout.h>
#include <libavutil\common.h>
#include <libavutil\imgutils.h>
#include <libavutil\mathematics.h>
#include <libavutil\samplefmt.h>
}
using namespace std;
void open_video(AVFormatContext * oc, AVCodec * codec, AVStream * st) {
int ret;
AVCodecContext * c;
c = st - > codec;
/*open codec */
cout << "probably starts here" << endl;
ret = avcodec_open2(c, codec, NULL);
cout << "and ends here" << endl;
if (ret < 0) {
cout << ("Could not open video codec") << endl;
}
}
/*This function will add a new stream to our file.
#param
oc -> Format context that the new stream will be added.
codec -> codec of the stream, this will be passed.
codec_id ->
chWidth->
chHeight->
*/
AVStream * addStream(AVFormatContext * oc, AVCodec ** codec, enum AVCodecID codec_id, int chWidth, int chHeight, int fps) {
AVCodecContext * c;
AVStream * st;
//find encoder of the stream, it passes this information to #codec, later on
//it will be used in encoding the video # avcodec_encode_video2 in loop.
* codec = avcodec_find_encoder(AV_CODEC_ID_H264);
if (( * codec) == NULL)
cout << "ERROR CAN NOT FIND ENCODER! ERROR! ERROR! AVCODEC_FIND_ENCODER FAILED !!!1 "
"" << endl;
if (!( * codec))
printf("Could not find encoder for ' %s ' ", avcodec_get_name(codec_id));
//create a new stream with the found codec inside oc(AVFormatContext).
st = avformat_new_stream(oc, * codec);
if (!st)
cout << " Cannot allocate stream " << endl;
//Setting the stream id.
//Since, there can be other streams in this AVFormatContext,
//we should find the first non used index. And this is oc->nb_streams(number of streams) - 1
st - > id = oc - > nb_streams - 1;
c = st - > codec;
//setting the stream's codec's properties.
c - > codec_id = codec_id;
c - > bit_rate = 4000000;
c - > width = chWidth;
c - > height = chHeight;
c - > time_base.den = fps;
//fps;
c - > time_base.num = 1;
c - > gop_size = 12;
c - > pix_fmt = AV_PIX_FMT_YUV420P;
if (c - > codec_id == AV_CODEC_ID_MPEG2VIDEO) {
/* just for testing, we also add B frames */
c - > max_b_frames = 2;
}
if (c - > codec_id == AV_CODEC_ID_MPEG1VIDEO) {
/* Needed to avoid using macroblocks in which some coeffs overflow.
* This does not happen with normal video, it just happens here as
* the motion of the chroma plane does not match the luma plane. */
c - > mb_decision = 2;
}
/* Some formats want stream headers to be separate. */
if (oc - > oformat - > flags & AVFMT_GLOBALHEADER)
c - > flags |= CODEC_FLAG_GLOBAL_HEADER;
//returning our lovely new brand stream.
return st;
}
int changeResolution(string source, int format) {
//Data members
struct SwsContext * sws_ctx = NULL;
AVFrame * pFrame = NULL;
AVFrame * outFrame = NULL;
AVPacket packet;
uint8_t * buffer = NULL;
uint8_t endcode[] = {
0,
0,
1,
0xb7
};
AVDictionary * optionsDict = NULL;
AVFormatContext * pFormatCtx = NULL;
AVFormatContext * outputContext = NULL;
AVCodecContext * pCodecCtx;
AVCodec * pCodec;
AVCodec * codec;
AVCodec * videoCodec;
AVOutputFormat * fmt;
AVStream * video_stream;
int changeWidth;
int changeHeight;
int frameFinished;
int numBytes;
int fps;
int lock = 0;
//Register all codecs & other important stuff. Vital!..
av_register_all();
//Selects the desired resolution.
if (format == 0) {
changeWidth = 320;
changeHeight = 180;
} else if (format == 1) {
changeWidth = 640;
changeHeight = 480;
} else if (format == 2) {
changeWidth = 960;
changeHeight = 540;
} else if (format == 3) {
changeWidth = 1024;
changeHeight = 768;
} else {
changeWidth = 1280;
changeHeight = 720;
}
// Open video file
int aaa;
aaa = avformat_open_input( & pFormatCtx, source.c_str(), NULL, NULL);
if (aaa != 0) {
cout << " cannot open input file \n" << endl;
cout << "aaa = " << aaa << endl;
return -1; // Couldn't open file
}
// Retrieve stream information
if (av_find_stream_info(pFormatCtx) < 0)
return -1; // Couldn't find stream information
//just checking duration casually for no reason
/*int64_t duration = pFormatCtx->duration;
cout << "the duration is " << duration << " " << endl;*/
//this writes the info about the file
av_dump_format(pFormatCtx, 0, 0, 0);
cin >> lock;
// Find the first video stream
int videoStream = -1;
int i;
for (i = 0; i < 3; i++)
if (pFormatCtx - > streams[i] - > codec - > codec_type == AVMEDIA_TYPE_VIDEO) {
videoStream = i;
cout << " lel \n ";
break;
}
if (videoStream == -1)
return -1; // Didn't find a video stream
// Get a pointer to the codec context for the video stream
pCodecCtx = pFormatCtx - > streams[videoStream] - > codec;
fps = pCodecCtx - > time_base.den;
//Find the decoder of the input file, for the video stream
pCodec = avcodec_find_decoder(pCodecCtx - > codec_id);
if (pCodec == NULL) {
fprintf(stderr, "Unsupported codec!\n");
return -1; // Codec not found
}
// Open codec, you must open it first, in order to use it.
if (avcodec_open2(pCodecCtx, pCodec, & optionsDict) < 0)
return -1; // Could not open codec
// Allocate video frame ( pFrame for taking the packets into, outFrame for processed frames to packet.)
pFrame = avcodec_alloc_frame();
outFrame = avcodec_alloc_frame();
i = 0;
int ret;
int video_frame_count = 0;
//Initiate the outFrame set the buffer & fill the properties
numBytes = avpicture_get_size(PIX_FMT_YUV420P, changeWidth, changeHeight);
buffer = (uint8_t * ) av_malloc(numBytes * sizeof(uint8_t));
avpicture_fill((AVPicture * ) outFrame, buffer, PIX_FMT_YUV420P, changeWidth, changeHeight);
int pp;
int frameNo = 0;
//allocate the outputContext, it will be the AVFormatContext of our output file.
//It will try to find the format by giving the file name.
avformat_alloc_output_context2( & outputContext, NULL, NULL, "myoutput.mp4");
//Cant find the file extension, using MPEG as default.
if (!outputContext) {
printf("Could not deduce output format from file extension: using MPEG.\n");
avformat_alloc_output_context2( & outputContext, NULL, "mpeg", "myoutput.mp4");
}
//Still cant set file extension, exit.
if (!outputContext) {
return 1;
}
//set AVOutputFormat fmt to our outputContext's format.
fmt = outputContext - > oformat;
video_stream = NULL;
//If fmt has a valid codec_id, create a new video stream.
//This function will set the streams codec & codecs desired properties.
//Stream's codec will be passed to videoCodec for later usage.
if (fmt - > video_codec != AV_CODEC_ID_NONE)
video_stream = addStream(outputContext, & videoCodec, fmt - > video_codec, changeWidth, changeHeight, fps);
//open the video using videoCodec. by avcodec_open2() i.e open the codec.
if (video_stream)
open_video(outputContext, videoCodec, video_stream);
//Creating our new output file.
if (!(fmt - > flags & AVFMT_NOFILE)) {
ret = avio_open( & outputContext - > pb, "toBeStreamed.264", AVIO_FLAG_WRITE);
if (ret < 0) {
cout << " cant open file " << endl;
return 1;
}
}
//Writing the header of format context.
//ret = avformat_write_header(outputContext, NULL);
if (ret >= 0) {
cout << "writing header success !!!" << endl;
}
//Start reading packages from input file.
while (av_read_frame(pFormatCtx, & packet) >= 0) {
// Is this a packet from the video stream?
if (packet.stream_index == videoStream) {
// Decode video package into frames
ret = avcodec_decode_video2(pCodecCtx, pFrame, & frameFinished, & packet);
if (ret < 0) {
printf(" Error decoding frame !!..");
return ret;
}
if (frameFinished) {
printf("video_frame n:%d coded_n:%d\n", video_frame_count++, pFrame - > coded_picture_number);
}
av_free_packet( & packet);
//do stuff with frame, in this case we are changing the resolution.
static struct SwsContext * img_convert_ctx_in = NULL;
if (img_convert_ctx_in == NULL) {
img_convert_ctx_in = sws_getContext(pCodecCtx - > width,
pCodecCtx - > height,
pCodecCtx - > pix_fmt,
changeWidth,
changeHeight,
PIX_FMT_YUV420P,
SWS_BICUBIC,
NULL,
NULL,
NULL);
}
//scale the frames
sws_scale(img_convert_ctx_in,
pFrame - > data,
pFrame - > linesize,
0,
pCodecCtx - > height,
outFrame - > data,
outFrame - > linesize);
//initiate the pts value
if (frameNo == 0)
outFrame - > pts = 0;
//calculate the pts value & set it.
outFrame - > pts += av_rescale_q(1, video_stream - > codec - > time_base, video_stream - > time_base);
//encode frames into packages. Package passed in #packet.
if (avcodec_encode_video2(outputContext - > streams[0] - > codec, & packet, outFrame, & pp) < 0)
cout << "Encoding frames into packages, failed. " << endl;
frameNo++;
//write the packages into file, resulting in creating a video file.
av_interleaved_write_frame(outputContext, & packet);
}
}
av_free_packet( & packet);
//av_write_trailer(outputContext);
avio_close(outputContext - > pb);
// Free the RGB image
av_free(buffer);
av_free(outFrame);
// Free the YUV frame
av_free(pFrame);
// Close the codec
avcodec_close(video_stream - > codec);
avcodec_close(pCodecCtx);
// Close the video file
avformat_close_input( & pFormatCtx);
return 0;
}
at the end of the process I get my desired file with desired codec & container & resolution.
My problem is, in a part of our project I need to get elementary video streams IN file. Such as example.264. However I can not add a stream without creating an AVFormatContext. I can not create an AVFormatContext because 264 files does not have a container,they are just raw video?, as far as I know.
I have tried the way in decoding_encoding.c which uses fwrite. However that example was for mpeg-2 codec and when I try to adapt that code to H264/AVC codec, I got "floating point division by zero" error from mediainfo and moreover, some of the properties of the video was not showing (such as FPS & playtime & quality factor). I think it has to do with the "endcode" the example adds at the end of the code. It is for mpeg-2. ( uint8_t endcode[] = { 0, 0, 1, 0xb7 }; )
Anyway, I would love to get a startpoint for this task. I have managed to come this far by using internet resources ( quite few & outdated for ffmpeg) but now I'm stuck a little.