FFmpeg av_interleaved_write_frame invalid parameter -22 - ffmpeg

Windows 7 64 bit environment. C# Windows Forms application calling FFmpeg libraries through C++ bridge DLL including avcodec-57.dll, avformat-57.dll, avutil-55.dll, swresample-2.dll and swscale-4.dll to write MPEG-4 file using H.264/MPEG-4 AVC codec. When writing a single MP4 file, never a problem. When writing multiple MP4 files concurrently, via multiple C# threads, occasionally get av_interleaved_write_frame failure -22 which is invalid parameter on one or two but never all files. Needless to say, the parameters never change. Does FFmpeg use temporary files? Is it possible that there is a fratricidal effect when using the same DLLs to write multiple files concurrently?
Edit: placed mutex at entry/exit to my write frame function, see source below, and can no longer reproduce the problem. It would appear something about FFmpeg is not thread-safe.
extern "C" __declspec(dllexport) int ffmpeg_write_video_frame(FFMPEG_CONTEXT *ffmpegContext, uint8_t *frameBuffer)
{
#ifdef SINGLE_THREAD
WaitForSingleObject(hMutex, INFINITE);
#endif
AVFrame *frame = ffmpeg_get_video_frame(&ffmpegContext->video, frameBuffer);
if (frame == NULL)
{
MessageBox(GetActiveWindow(), "ffmpeg_get_video_frame returned NULL", "ffmpeg_write_video_frame", MB_OK);
#ifdef SINGLE_THREAD
ReleaseMutex(hMutex);
#endif
return(-1);
}
AVPacket pkt = { 0 };
av_init_packet(&pkt);
// encode the image
int got_packet = 0;
int result = avcodec_encode_video2(ffmpegContext->video.avCodecContext, &pkt, frame, &got_packet);
if (result < 0)
{
char text[256];
sprintf_s(text, sizeof(text), "avcodec_encode_videos failure=%d", result);
MessageBox(GetActiveWindow(), text, "ffmpeg_write_video_frame", MB_OK);
#ifdef SINGLE_THREAD
ReleaseMutex(hMutex);
#endif
return(result);
}
// if the encoder has produced an output packet
if (got_packet)
{
result = ffmpeg_write_frame(ffmpegContext->avFormatContext, &ffmpegContext->video.avCodecContext->time_base, ffmpegContext->video.avStream, &pkt);
if (result < 0)
{
char text[256];
sprintf_s(text, sizeof(text), "ffmpeg_write_frame failure=%d", result);
MessageBox(GetActiveWindow(), text, "ffmpeg_write_video_frame", MB_OK);
#ifdef SINGLE_THREAD
ReleaseMutex(hMutex);
#endif
return(result);
}
}
#ifdef SINGLE_THREAD
ReleaseMutex(hMutex);
#endif
return (0);
}
extern "C" int ffmpeg_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. */
#if 0
log_packet(fmt_ctx, pkt);
#endif
int result = av_interleaved_write_frame(fmt_ctx, pkt);
if (result < 0)
{
char text[256];
sprintf_s(text, sizeof(text), "av_interleaved_write_frame failure=%d", result);
MessageBox(GetActiveWindow(), text, "ffmpeg_write_frame", MB_OK);
}
return(result);
}

Related

How to force an input frame rate on libav for mjpeg

I am using libav to parsing a MJPEG Stream to get the packet data for resending it over an websocket, now I am facing the issue that ffmpeg use only 25 FPS. I know the Stream has 60FPS for 100%
These are the values after open and read the stream Informations:
avg_frame_rate = 0, r_frame_rate = 25/1, time_base = 1/25
I tried to set all of them to a setting for 60FPS, but this looks has no effect.
I have set time_base to 1/60 and also frame rates to 60 but none of them are making any difference.
Because its an MJPEG Stream libav needs to guess the framerate, but I don't know why setting time_base or framerate does not have any effect.
Maybe someone could help me how I could force 60 FPS for parsing an MJEPG Stream, this would be great.
Thank u
This is just an Illustration of my code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <libavutil/avutil.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
int main(int argc, char *argv[]) {
AVFormatContext *fmt_ctx = NULL;
AVCodecContext *codec_ctx = NULL;
AVCodec *codec = NULL;
AVPacket pkt;
if (argc < 2) {
fprintf(stderr, "Usage: %s <mjpeg-stream-url>\n", argv[0]);
exit(1);
}
av_register_all();
if (avformat_open_input(&fmt_ctx, argv[1], NULL, NULL) < 0) {
fprintf(stderr, "Could not open stream '%s'\n", argv[1]);
exit(1);
}
if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
fprintf(stderr, "Could not find stream information\n");
exit(1);
}
int video_stream_index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &codec, 0);
if (video_stream_index < 0) {
fprintf(stderr, "Could not find video stream\n");
exit(1);
}
AVStream *video_stream = fmt_ctx->streams[video_stream_index];
stream->time_base = (AVRational) { 1, 60};
stream->avg_frame_rate = (AVRational) { 60, 1 };
stream->r_frame_rate = (AVRational) { 60, 1 };
av_init_packet(&pkt);
while (av_read_frame(fmt_ctx, &pkt) >= 0) {
if (pkt.stream_index == video_stream_index) {
// Sending it to an websocket ....
}
av_packet_unref(&pkt);
}
avformat_close_input(&fmt_ctx);
avformat_free_context(fmt_ctx);
return 0;
}
The AVDictionary sets additional/specific parameters to endpoints and if you call it while opening the endpoint, it uses these specific parameters to open the endpoint.
It could take multiple key - value pairs and applies all of them to the endpoint.
I suppose creating an AVDictionay and passing a "framerate", "60" or may be "framerate" "60000/1000" parameter could solve your problem. Or if your source supports format_code then you could also use the format code something like "format_code", "Hp60" in the AVDictionary.
AVDictionary *options{nullptr};
// You should find the right parameter name
// like "frame_rate", "format_code", "sample_rate" etc.
// You can also set multiple options there!
// you may put all the possibilities once!
if(av_dict_set(&options, "framerate", "60", 0) < 0) {
fprintf(stderr, "Could not set the option!\n");
exit(1);
}
if (avformat_open_input(&fmt_ctx, argv[1], NULL, &options) < 0) {
fprintf(stderr, "Could not open stream '%s'\n", argv[1]);
exit(1);
}

FFmpeg doesn't use GPU

I got the latest version binaries of ffmpeg from here. When I examine CPU and GPU usages when I play a video by its ffplay, I see that GPU is used during play. Not much using of CPU also indicates it. But when I get the latest version sources from the original site, I can't use GPU. To clarify, I include a player test program I wrote until now. When I uncomment the line which includes avcodec_find_decoder_by_name("h264_cuvid"), I get error -1. The error happens in avcodec_open2 with the description of Operation not permitted.
CString format(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
char buf[512];
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
return buf;
}
int CplayerDlg::play()
{
FILE *fp = fopen("video_files/1010.brf", "rb");
if (!fp)
{
AfxMessageBox("can't open video file");
return -1;
}
RecordFrame frame;
RecordHeader hdr;
fread(&frame, sizeof(frame), 1, fp);
if (frame.frameType != FRAME_TYPE_HEADER)
{
AfxMessageBox("record file doesn't begin with header");
return -1;
}
fread(&hdr, sizeof(hdr), 1, fp);
GetDlgItem(IDC_DIM)->SetWindowText(format("%dx%d", hdr.width, hdr.height));
GetDlgItem(IDC_CODEC_ID)->SetWindowText(format("%d", hdr.codecId));
GetDlgItem(IDC_PIXEL_FORMAT)->SetWindowText(format("%d", hdr.pixelFormat));
GetDlgItem(IDC_TIMEBASE)->SetWindowText(format("%d/%d", hdr.timebaseNum, hdr.timebaseDen));
AVCodec *pCodec;
#if 0
#define CHECK(decoder)\
pCodec = avcodec_find_decoder_by_name(#decoder);\
AfxMessageBox(pCodec ? #decoder " found" : "can't find " #decoder);
CHECK(h264_cuvid);
#undef CHECK
#endif
pCodec = avcodec_find_decoder(AV_CODEC_ID_H264);
//pCodec = avcodec_find_decoder_by_name("h264_cuvid");
if (!pCodec)
{
AfxMessageBox("can't find h264 decoder");
return -1;
}
AVCodecContext *pCodecContext = avcodec_alloc_context3(pCodec);
if (!pCodecContext)
{
AfxMessageBox("can't allocate codec context");
return -1;
}
#if 0
// enumerating available codecs
//av_register_all();
avcodec_register_all();
AVCodec *current_codec = av_codec_next(NULL);
while (current_codec != NULL)
{
TRACE("%s\n", current_codec->name);
current_codec = av_codec_next(current_codec);
}
#endif
int err = avcodec_open2(pCodecContext, pCodec, NULL);
if (err != 0)
{
char buf[AV_ERROR_MAX_STRING_SIZE];
av_make_error_string(buf, AV_ERROR_MAX_STRING_SIZE, err);
char buf2[AV_ERROR_MAX_STRING_SIZE];
sprintf(buf2, "%d (%x): %s\n", err, err, buf);
AfxMessageBox(buf2);
return -1;
}
AfxMessageBox("operation completed successfully");
fclose(fp);
return 0;
}

Decoding of 16bit gray image encoded with FFV1

I have a problem with decoding of gray images encoded with FFV1 codec.
I successfully encode 16 bit gray image (with avcodec_receive_packet(...) function) and save AvPacket data to file. Then I read this data from file and try to decode (with avcodec_decode_video2 or avcodec_send_packet/avcodec_receive_frame) with no success:
when I try to decode packet with avcodec_decode_video2 function I get an error "Access violation occurred, unable to write location 0x0000000000000000".
when I try to decode packet with avcodec_send_packet/avcodec_receive_frame functions I get an error "chroma shift parameters 7 0 are invalid".
I compared packets after encoding and before decoding and all fields and values seems to be the same. I even try to decode packet just after avcodec_receive_packet (encoding function), however with the same error.
I use the 4.0 version of ffmpeg and the program is based on decode_video.c and encode_video.c examples.
When I use containers (eg. avi) to support read/write encoded images from file (based on demuxing_decoding.c and muxing.c examples) I successfully encode and decode frames with FFV1. However I cannot use containers, because I want to encode frames with different resolutions and mix few video sources together. Additionally the compression level is significantly lower (falls from 2.9 to 2.2) for few hundred of images, what is also very surprising.
So my question is how to correctly save/read (from binary file not container) and prepare AVPacker for decoding with FFV1.
Any help is greatly appreciated.
The decoding code:
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
#include <libavutil/imgutils.h>
}
#pragma warning(disable: 4996)
#define INBUF_SIZE 4096
#define FF_INPUT_BUFFER_PADDING_SIZE 64
uint8_t endcode[4];
AVCodecContext *c, c2;
AVCodec *codec;
int i, ret, x, y;
AVFrame *frame;
AVPacket *pkt, *pkt_temp;
FILE *encodedVideoFile;
AVDictionary *opts = NULL;
uint8_t *video_dst_data[4] = { NULL };
int video_dst_linesize[4];
int imageSize;
uint8_t inbuf[INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
/* flush the encoder */
frame = NULL;
encode();
/* add sequence end code to have a real MPEG file */
//fwrite(endcode, 1, sizeof(endcode), encodedVideoFile);
fclose(encodedVideoFile);
avcodec_free_context(&c);
av_frame_free(&frame);
av_packet_free(&pkt);
}
void initDecoding(const char *filename)
{
/* set end of buffer to 0 (this ensures that no overreading happens for damaged MPEG streams) */
memset(inbuf + INBUF_SIZE, 0, AV_INPUT_BUFFER_PADDING_SIZE);
/* find the MPEG-1 video decoder */
codec = avcodec_find_decoder(AV_CODEC_ID_FFV1);
if (!codec) {
fprintf(stderr, "Codec not found\n");
exit(1);
}
c = avcodec_alloc_context3(codec);
if (!c) {
fprintf(stderr, "Could not allocate video codec context\n");
exit(1);
}
/* resolution must be a multiple of two */
c->width = 1280;
c->height = 484;
/* frames per second */
c->time_base.den = 1;
c->time_base.num = 10;
c->bits_per_raw_sample = 16;
c->framerate.den = 10;
c->framerate.num = 1;
c->pix_fmt = AV_PIX_FMT_GRAY16;
//Version of FFV1 codec
c->level = 3;
/* Init the decoders, with or without reference counting */
av_dict_set(&opts, "refcounted_frames", 0 ? "1" : "0", 0);
if ((ret = avcodec_open2(c, codec, &opts)) < 0) {
return;
}
if (avcodec_open2(c, codec, NULL) < 0) {
fprintf(stderr, "Could not open codec\n");
exit(1);
}
ret = av_image_alloc(video_dst_data, video_dst_linesize,
c->width, c->height, c->pix_fmt, 4);
if (ret < 0) {
fprintf(stderr, "Could not allocate raw video buffer\n");
}
encodedVideoFile = fopen(filename, "rb");
if (!encodedVideoFile) {
fprintf(stderr, "Could not open %s\n", filename);
exit(1);
}
frame = av_frame_alloc();
if (!frame) {
fprintf(stderr, "Could not allocate video frame\n");
exit(1);
}
frame->format = c->pix_fmt;
frame->width = c->width;
frame->height = c->height;
ret = av_frame_get_buffer(frame, 32);
if (ret < 0) {
fprintf(stderr, "Could not allocate the video frame data\n");
exit(1);
}
/* make sure the frame data is writable */
ret = av_frame_make_writable(frame);
if (ret < 0)
exit(1);
}
void closeDecoding()
{
fclose(encodedVideoFile);
av_parser_close(parser);
avcodec_free_context(&c);
av_frame_free(&frame);
av_packet_free(&pkt);
}
void decodePacket()
{
size_t data_size;
int *got_frame = 0;
read_packt_from_file(pkt, encodedVideoFile);
ret = av_frame_is_writable(frame);
//First decoding function
/*ret = avcodec_decode_video2(c, frame, got_frame, pkt);
if (ret < 0) {
fprintf(stderr, "Error decoding video frame (%s)\n");
}*/
ret = avcodec_send_packet(c, pkt);
if (ret < 0) {
fprintf(stderr, "Error sending a packet for decoding\n");
exit(1);
}
while (ret >= 0) {
ret = avcodec_receive_frame(c, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
return;
else if (ret < 0) {
fprintf(stderr, "Error during decoding\n");
exit(1);
}
printf("saving frame %3d\n", c->frame_number);
fflush(stdout);
}
}
size_t read_packt_from_file(AVPacket *packet, FILE *file)
{
size_t ret = 0;
int size;
uint8_t * data;
//av_packet_from_data
ret = fread(packet, sizeof(AVPacket), 1, file);
size = packet->size;
data = new uint8_t[size];
ret = fread(data, size, 1, file);
av_new_packet(packet, size);
av_packet_from_data(packet, data, size);
return ret;
}
//To write encoded AVPacket
size_t write_packt_to_file(AVPacket *packet, FILE *file)
{
size_t ret = 0;
ret = fwrite(packet, sizeof(AVPacket), 1, file);
ret = fwrite(packet->data, packet->size, 1, file);
if (packet->buf) {
fwrite(packet->buf->data, packet->buf->size, 1, file);
}
fflush(file);
return ret;
}

Why there is no AVFrame->data[2] data when decode h264 by ffmpeg use "h264_cuvid"

env: ubuntu 16.04 64 bit; ffmpeg 3.3.2 build whih cuda cuvid libnpp...
use ffmpeg cmd: ffmpeg -vsync 0 -c:v h264_cuvid -i test.264 -f rawvideo test.yuv works fine, the generated yuv file is ok.
BUT When I decode this 264 file by my code use 'h264_cuvid' decoder, something problem happens, this is my code:
#include <stdio.h>
#define __STDC_CONSTANT_MACROS
#ifdef _WIN32
//Windows
extern "C"
{
#include "libavcodec/avcodec.h"
};
#else
//Linux...
#ifdef __cplusplus
extern "C"
{
#endif
#include <libavcodec/avcodec.h>
#ifdef __cplusplus
};
#endif
#endif
//test different codec
#define TEST_H264 1
#define TEST_HEVC 0
int main(int argc, char* argv[])
{
AVCodec *pCodec;
AVCodecContext *pCodecCtx= NULL;
AVCodecParserContext *pCodecParserCtx=NULL;
FILE *fp_in;
FILE *fp_out;
AVFrame *pFrame;
const int in_buffer_size=4096;
unsigned char in_buffer[in_buffer_size + FF_INPUT_BUFFER_PADDING_SIZE]= {0};
unsigned char *cur_ptr;
int cur_size;
AVPacket packet;
int ret, got_picture;
#if TEST_HEVC
enum AVCodecID codec_id=AV_CODEC_ID_HEVC;
char filepath_in[]="bigbuckbunny_480x272.hevc";
#elif TEST_H264
AVCodecID codec_id=AV_CODEC_ID_H264;
char filepath_in[]="2_60_265to264.264";
#else
AVCodecID codec_id=AV_CODEC_ID_MPEG2VIDEO;
char filepath_in[]="bigbuckbunny_480x272.m2v";
#endif
char filepath_out[]="mainSend.yuv";
int first_time=1;
//av_log_set_level(AV_LOG_DEBUG);
avcodec_register_all();
// pCodec = avcodec_find_decoder(codec_id);
pCodec = avcodec_find_decoder_by_name("h264_cuvid");
if (!pCodec)
{
printf("Codec not found\n");
return -1;
}
pCodecCtx = avcodec_alloc_context3(pCodec);
if (!pCodecCtx)
{
printf("Could not allocate video codec context\n");
return -1;
}
pCodecParserCtx=av_parser_init(pCodec->id);
if (!pCodecParserCtx)
{
printf("Could not allocate video parser context\n");
return -1;
}
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
{
printf("Could not open codec\n");
return -1;
}
//Input File
fp_in = fopen(filepath_in, "rb");
if (!fp_in)
{
printf("Could not open input stream\n");
return -1;
}
//Output File
fp_out = fopen(filepath_out, "wb");
if (!fp_out)
{
printf("Could not open output YUV file\n");
return -1;
}
pFrame = av_frame_alloc();
av_init_packet(&packet);
while (1)
{
cur_size = fread(in_buffer, 1, in_buffer_size, fp_in);
if (cur_size == 0)
break;
cur_ptr=in_buffer;
while (cur_size>0)
{
int len = av_parser_parse2(
pCodecParserCtx, pCodecCtx,
&packet.data, &packet.size,
cur_ptr, cur_size,
AV_NOPTS_VALUE, AV_NOPTS_VALUE, AV_NOPTS_VALUE);
cur_ptr += len;
cur_size -= len;
if(packet.size==0)
continue;
//Some Info from AVCodecParserContext
printf("[Packet]Size:%6d\t",packet.size);
switch(pCodecParserCtx->pict_type)
{
case AV_PICTURE_TYPE_I:
printf("Type:I\tNumber:%4d\n",pCodecParserCtx->output_picture_number);
break;
case AV_PICTURE_TYPE_P:
printf("Type:P\t");
break;
case AV_PICTURE_TYPE_B:
printf("Type:B\t");
break;
default:
printf("Type:Other\t");
break;
}
printf("Number:%4d\n",pCodecParserCtx->output_picture_number);
AVFrame* myFrame = av_frame_alloc();
ret = avcodec_decode_video2(pCodecCtx, myFrame, &got_picture, &packet);
if (ret < 0)
{
printf("Decode Error.\n");
return ret;
}
if (got_picture)
{
if(first_time)
{
printf("\nCodec Full Name:%s\n",pCodecCtx->codec->long_name);
printf("width:%d\nheight:%d\n\n",pCodecCtx->width,pCodecCtx->height);
first_time=0;
}
//Y, U, V
for(int i=0; i<myFrame->height; i++)
{
fwrite(myFrame->data[0]+myFrame->linesize[0]*i,1,myFrame->width,fp_out);
}
for(int i=0; i<myFrame->height/2; i++)
{
fwrite(myFrame->data[1]+myFrame->linesize[1]*i,1,myFrame->width/2,fp_out);
}
for(int i=0; i<myFrame->height/2; i++)
{
fwrite(myFrame->data[2]+myFrame->linesize[2]*i,1,myFrame->width/2,fp_out);
}
// printf("pframe's width height %d %d\t key frame %d\n",myFrame->width,myFrame->height,myFrame->key_frame);
printf("Succeed to decode 1 frame!\n");
av_frame_free(&myFrame);
}
}
}
fclose(fp_in);
fclose(fp_out);
av_parser_close(pCodecParserCtx);
av_frame_free(&pFrame);
avcodec_close(pCodecCtx);
av_free(pCodecCtx);
return 0;
}
In this demo code, I call h264_cuvid by vcodec_find_decoder_by_name("h264_cuvid");
BUT the code crash at fwrite(myFrame->data[2]+myFrame->linesize[2]*i,1,myFrame->width/2,fp_out);
So after debug with codeblocks, I found that there is no data in myFrame->data[2] codeblocks watching window
Any suggestion? thanks!
"h264" decoder's frame pix format is AV_PIX_FMT_YUV420P
BUT "h264_cuvid" decoder's frame pix format is AV_PIX_FMT_NV12
so, edit code to
for(int i=0; i<myFrame->height; i++)
{
fwrite(myFrame->data[0]+myFrame->linesize[0]*i,1,myFrame->width,fp_out);
}
for(int i=0; i<myFrame->height/2; i++)
{
fwrite(myFrame->data[1]+myFrame->linesize[1]*i,1,myFrame->width,fp_out);
}
Works fine

avcodec_open2: PCM channels out of bounds

I am trying to read an audio RTP stream in my application, but I am getting this error:
[pcm_mulaw # 03390580] PCM channels out of bounds
I can read the RTP stream fine with ffplay:
ffplay -i test.sdp -protocol_whitelist file,udp,rtp
I generate the RTP stream using this command:
ffmpeg -re -f lavfi -i aevalsrc="sin(400*2*PI*t)" -ar 8000 -f mulaw -f rtp rtp://127.0.0.1:8554
// SDP
v=0
o=- 0 0 IN IP4 127.0.0.1
s=No Name
c=IN IP4 127.0.0.1
t=0 0
a=tool:libavformat 57.25.101
m=audio 8554 RTP/AVP 0
b=AS:64
And here is my source code:
#include "stdafx.h"
#include <math.h>
extern "C"
{
#include <libavutil/opt.h>
#include <libavcodec/avcodec.h>
#include <libavutil/channel_layout.h>
#include <libavutil/common.h>
#include <libavutil/imgutils.h>
#include <libavutil/mathematics.h>
#include <libavutil/samplefmt.h>
#include <libavformat/avformat.h>
}
#define AUDIO_INBUF_SIZE 20480
#define AUDIO_REFILL_THRESH 4096
#define ERRBUFFLEN 200
char errbuf[ERRBUFFLEN];
#define av_err2str(ret) av_strerror(ret, errbuf, ERRBUFFLEN)
/*
* Audio decoding.
*/
static void audio_decode_example(const char *outfilename, const char *filename)
{
AVCodec *inCodec;
AVCodecContext *inCodecCtx = NULL;
int len;
FILE *f, *outfile;
uint8_t inbuf[AUDIO_INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
AVPacket avpkt;
AVFrame *decoded_frame = NULL;
AVFormatContext *inFormatCtx = NULL;
AVFrame *inFrame = NULL;
AVFrame *outFrame = NULL;
int ret;
av_init_packet(&avpkt);
AVDictionary *d = NULL; // "create" an empty dictionary
int listen = false;
listen = true;
if (listen)
{
av_dict_set(&d, "protocol_whitelist", "file,udp,rtp", 0); // add an entry
printf("Listening mode.\n");
}
else {
printf("Connecting mode.\n");
}
// Open video file
ret = avformat_open_input(&inFormatCtx, filename, NULL, &d);
if (ret <0)
{
printf_s("Failed: cannot open input.\n");
av_strerror(ret, errbuf, ERRBUFFLEN);
fprintf(stderr, "avformat_open_input() fail: %s\n", errbuf);
exit(1);
}
printf_s("Retrieve stream information.\n");
ret = avformat_find_stream_info(inFormatCtx, NULL);
if (ret <0)
{
printf_s("Failed: cannot find stream.\n");
av_strerror(ret, errbuf, ERRBUFFLEN);
fprintf(stderr, "avformat_find_stream_info() fail: %s\n", errbuf);
exit(1);
}
av_dump_format(inFormatCtx, 0, filename, 0);
int stream_idx = -1;
for (int i = 0; i < inFormatCtx->nb_streams; i++)
if (inFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
stream_idx = i;
break;
}
if (stream_idx == -1)
{
fprintf(stderr, "Video stream not found\n");
exit(1);
}
inCodec = avcodec_find_decoder(inFormatCtx->streams[stream_idx]->codec->codec_id);
if (!inCodec) {
fprintf(stderr, "Codec not found\n");
exit(1);
}
inCodecCtx = avcodec_alloc_context3(inCodec);
if (!inCodecCtx) {
fprintf(stderr, "Could not allocate audio codec context\n");
exit(1);
}
/* Error here */
ret = avcodec_open2(inCodecCtx, inCodec, NULL);
if (ret < 0) {
fprintf(stderr, "Could not open codec: %s\n", av_err2str(ret));
exit(1);
}
(...more code)
I know something is wrong, but what is it? Suggestions and tips are much appreciated.
I found out that the stream attributes were not set automatically, so I had to manually set them before calling avcodec_open2():
inCodecCtx->sample_rate = 8000;
inCodecCtx->sample_fmt = AV_SAMPLE_FMT_S16;
inCodecCtx->channels = 1;
inCodecCtx->channel_layout = AV_CH_LAYOUT_MONO;
Hope this helps someone who encountered the same issue as I do.
There's also a dedicated function in avcodec.h :
int error = avcodec_parameters_to_context(inCodecCtx, inFormatCtx->streams[stream_idx]->codecpar);
if (error < 0) {
// something went wrong
}
(See https://www.ffmpeg.org/doxygen/3.2/demuxing__decoding_8c_source.html, line 182).
Thanks, you helped me :-D
Just wanted to add, if you don't know them, you can get these parameters from the file.
Here is my code searching for an audio stream, getting a decoder for it, and setting up the parameters from the formatContext.
Note that my code is Scala calling the Java-CPP wrapper around FFMEG
val formatContext = chkNull(avformat.avformat_alloc_context())
val inputFormat = avformat.av_find_input_format(format)
if (inputFormat == null) throw new Error(s"Format '${format}' is not supported")
formatContext.iformat(inputFormat)
chk(avformat.avformat_open_input(formatContext, "<path to audio file goes here>", null, null))
val audioStreams = (0 until formatContext.nb_streams) filter { i: Int =>
formatContext.streams(i).codecpar().codec_type() == avutil.AVMEDIA_TYPE_AUDIO
}
val audioStream = audioStreams.size match {
case 0 => throw new Error("No Audio Stream found")
case 1 => audioStreams.head
case _ => throw new Error("More than one Audio Streams found")
}
val codecParameters = formatContext.streams(audioStream).codecpar()
val decoder = chkNull(avcodec.avcodec_find_decoder(codecParameters.codec_id()))
val codecContext = chkNull(avcodec.avcodec_alloc_context3(decoder))
codecContext.sample_rate(codecParameters.sample_rate())
codecContext.sample_fmt(codecParameters.format())
codecContext.channels(codecParameters.channels())
codecContext.channel_layout(codecParameters.channel_layout())
chk(avcodec.avcodec_open2(codecContext, null, null.asInstanceOf[AVDictionary]))

Resources