Writing only video (no audio) file using ffmpeg. av_write_header fails - ffmpeg

I have RTP packets with VP8 encoded data. I want to write it to a mkv file or webm file. I tried a bit, but I have not been successful yet. My code is as below
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <math.h>
#include <libavutil/avassert.h>
#include <libavutil/channel_layout.h>
#include <libavutil/opt.h>
#include <libavutil/mathematics.h>
#include <libavutil/timestamp.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
bool mfmedia_init_ffmpeg();
void mfmedia_ffprint(void *handle, int cnt, const char *format, va_list valist);
int main()
{
mfmedia_init_ffmpeg();
return 0;
}
bool mfmedia_init_ffmpeg()
{
bool ret = false;
AVCodecContext* context;
AVCodec* codec;
AVFormatContext* format;
AVStream* stream;
unsigned fps = 24;
unsigned width = 768;
unsigned height = 608;
av_register_all();
int err = 0;
char errorLog[128] = { 0 };
av_log_set_level(AV_LOG_TRACE);
av_log_set_callback(mfmedia_ffprint);
err = avformat_alloc_output_context2(&format, NULL, NULL, "o.webm");
if (err < 0)
{
printf("Cannot allocate output context: %s\n", av_make_error_string(errorLog, 128, err));
goto last;
}
codec = avcodec_find_encoder(AV_CODEC_ID_VP8);
if (!codec)
{
printf("Cannot find an encoder\n");
goto last;
}
context = avcodec_alloc_context3(codec);
if (!context)
{
printf("Cannot allocate a codec context\n");
goto last;
}
context->pix_fmt = AV_PIX_FMT_YUV420P;
context->width = width;
context->height = height;
context->time_base = (AVRational){1, fps};
err = avcodec_open2(context, codec, NULL);
if(err < 0)
{
printf("Cannot open codec: %s\n", av_make_error_string(errorLog, 128, err));
goto last;
}
stream = avformat_new_stream(format, codec);
if (!stream)
{
printf("Cannot create a new stream\n");
goto last;
}
//av_dump_format(format, 0, "o.webm", 1);
err = avio_open(&format->pb, "o.webm", AVIO_FLAG_WRITE);
if(err < 0)
{
printf("Cannot open output: %s\n", av_make_error_string(errorLog, 128, err));
goto last;
}
err = avformat_write_header(format, NULL);
if(err < 0)
{
printf("Cannot write header to stream: %s\n", av_make_error_string(errorLog, 128, err));
goto last;
}
ret = true;
last:
return ret;
}
void mfmedia_ffprint(void *handle, int cnt, const char *format, va_list valist)
{
char *log_buf = (char *)malloc(38192);
int length;
if(log_buf)
{
time_t rawtime;
time ( &rawtime );
length = vsprintf(log_buf ,format, valist);
length += sprintf((log_buf + length), " : %s ", ctime (&rawtime));
*(log_buf + length) = 0x0;
printf("%s", log_buf);
fflush(stdout);
free(log_buf);
}
}
It is failing when I call avformat_write_header.
From trace log (towards end) I see
Setting default whitelist 'file,crypto'
: Fri Jan 19 16:58:57 2018
Using AVStream.codec to pass codec parameters to muxers is deprecated, use AVStream.codecpar instead.
: Fri Jan 19 16:58:57 2018
dimensions not set
: Fri Jan 19 16:58:57 2018
Cannot write header to stream: Invalid argument
Please let me know why avformat_write_header is failing.

This should work, enter this code snipped right above of: //av_dump_format(format, 0, "o.webm", 1);
/* copy the stream parameters to the muxer */
err = avcodec_parameters_from_context(stream->codecpar, context);
if (err < 0) {
fprintf(stderr, "Could not copy the stream parameters\n");
exit(1);
}

Related

FFMPEG transcoder producing broken video

I have the following code to transcode video which is closely related to the FFMPEG transcoding example.
However it produced broken video as shown:
It seems like the i-frames are decoded correctly, but the p and b frames are out of order? I thought av_interleaved_write_frame() would rectify that for me. It also seems like the libx264 is not creating any extradata which I thought it would.
Could someone please help me work out why?
Many thanks
#include <stdbool.h>
#include <stdio.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavutil/mathematics.h>
#include <libavutil/opt.h>
#define DEBUG(level, format, ...) fprintf(stderr, format "\n", ##__VA_ARGS__)
#define stringify2(var) #var
#define stringify(var) stringify2(var)
#define RASSERT(cond, ...) do { \
if (!(cond)) { \
DEBUG(LOG_FATAL, __FILE__ ":" stringify(__LINE__) " " "Assertion failed! " #cond ". " __VA_ARGS__); \
abort(); \
} \
} while (0)
#define FFCHECK(ret, func) RASSERT(ret == 0, #func " failed: %s (%d)", av_err2str(ret), ret)
typedef struct decode_context {
AVFormatContext *format;
AVCodecContext *videoCodec;
AVCodecContext *audioCodec;
AVStream *videoStream;
AVStream *audioStream;
} decode_context_t;
typedef struct encode_context {
AVFormatContext *format;
AVCodecContext *videoCodec;
AVCodecContext *audioCodec;
AVStream *videoStream;
AVStream *audioStream;
} encode_context_t;
void open_input(decode_context_t *dec, const char *file) {
int ret;
ret = avformat_open_input(&dec->format, file, NULL, NULL);
FFCHECK(ret, "avformat_open_input()");
ret = avformat_find_stream_info(dec->format, NULL);
FFCHECK(ret, "avformat_find_stream_info()");
for (unsigned int i = 0; i < dec->format->nb_streams; ++i) {
AVStream * stream = dec->format->streams[i];
enum AVMediaType type = stream->codecpar->codec_type;
switch (type) {
case AVMEDIA_TYPE_VIDEO:
if (dec->videoStream)
break;
dec->videoStream = stream;
break;
case AVMEDIA_TYPE_AUDIO:
dec->audioStream = stream;
if (dec->audioStream)
break;
break;
default:
break;
}
}
RASSERT(dec->videoStream != NULL, "Didn't find video stream");
const AVCodec * codec = avcodec_find_decoder(dec->videoStream->codecpar->codec_id);
RASSERT(codec, "Failed to find decoder");
dec->videoCodec = avcodec_alloc_context3(codec);
RASSERT(dec->videoCodec, "avcodec_alloc_context3() failed");
ret = avcodec_parameters_to_context(dec->videoCodec, dec->videoStream->codecpar);
FFCHECK(ret, "avcodec_parameters_to_context()");
dec->videoCodec->framerate = av_guess_frame_rate(dec->format, dec->videoStream, NULL);
ret = avcodec_open2(dec->videoCodec, codec, NULL);
FFCHECK(ret, "avcodec_open2()");
}
void open_output(encode_context_t *enc, const char *file, decode_context_t *dec) {
int ret;
ret = avformat_alloc_output_context2(&enc->format, NULL, NULL, file);
FFCHECK(ret, "avformat_alloc_output_context2()");
enc->videoStream = avformat_new_stream(enc->format, NULL);
RASSERT(enc->videoStream, "avformat_new_stream() failed");
enc->videoStream->id = enc->format->nb_streams - 1;
const AVCodec *codec = avcodec_find_encoder_by_name("libx264");
RASSERT(codec, "Failed to find encoder");
enc->videoCodec = avcodec_alloc_context3(codec);
RASSERT(enc->videoCodec, "avcodec_alloc_context3() failed");
enc->videoCodec->bit_rate = 400000;
enc->videoCodec->width = dec->videoCodec->width;
enc->videoCodec->height = dec->videoCodec->height;
enc->videoCodec->sample_aspect_ratio = dec->videoCodec->sample_aspect_ratio;
enc->videoCodec->time_base = av_inv_q(dec->videoCodec->framerate);
//enc->videoCodec->gop_size = 12;
//enc->videoCodec->max_b_frames = 2;
enc->videoCodec->pix_fmt = dec->videoCodec->pix_fmt;
enc->videoCodec->framerate = dec->videoCodec->framerate;
if (codec->id == AV_CODEC_ID_H264) {
av_opt_set(enc->videoCodec->priv_data, "preset", "slow", 0);
av_opt_set(enc->videoCodec->priv_data, "profile", "high", 0);
av_opt_set(enc->videoCodec->priv_data, "level", "4.1", 0);
}
if (enc->format->flags & AVFMT_GLOBALHEADER)
enc->videoCodec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
ret = avcodec_open2(enc->videoCodec, codec, NULL);
FFCHECK(ret, "avcodec_open2()");
ret = avcodec_parameters_from_context(enc->videoStream->codecpar, enc->videoCodec);
FFCHECK(ret, "avcodec_parameters_from_context()");
//enc->videoStream->time_base = enc->videoCodec->time_base;
//enc->videoStream->codecpar->extradata = enc->videoCodec->extradata;
//enc->videoStream->codecpar->extradata_size = enc->videoCodec->extradata_size;
av_dump_format(enc->format, 0, file, 1);
ret = avio_open(&enc->format->pb, file, AVIO_FLAG_WRITE);
FFCHECK(ret, "avio_open()");
ret = avformat_write_header(enc->format, NULL);
FFCHECK(ret, "avformat_write_header()");
}
int main(int argc, const char * argv[]) {
int ret;
if (argc < 3) {
fprintf(stderr, "%s input output\n", argv[0]);
return 1;
}
decode_context_t dec_ctx = {};
decode_context_t *dec = &dec_ctx;
encode_context_t enc_ctx = {};
encode_context_t *enc = &enc_ctx;
open_input(dec, argv[1]);
open_output(enc, argv[2], dec);
while (true) {
AVPacket *packet = av_packet_alloc();
ret = av_read_frame(dec->format, packet);
if (ret < 0)
break;
if (packet->stream_index == dec->videoStream->index) {
ret = avcodec_send_packet(dec->videoCodec, packet);
if (ret == AVERROR(EAGAIN)) {
AVFrame * frame = av_frame_alloc();
while (true) {
ret = avcodec_receive_frame(dec->videoCodec, frame);
if (ret == AVERROR(EAGAIN))
break;
FFCHECK(ret, "avcodec_receive_frame()");
ret = avcodec_send_frame(enc->videoCodec, frame);
if (ret == AVERROR(EAGAIN)) {
AVPacket *pkt = av_packet_alloc();
while (true) {
ret = avcodec_receive_packet(enc->videoCodec, pkt);
if (ret == AVERROR(EAGAIN))
break;
FFCHECK(ret, "avcodec_receive_packet()");
pkt->stream_index = enc->videoStream->id;
av_packet_rescale_ts(pkt, dec->videoStream->time_base, enc->videoStream->time_base);
ret = av_interleaved_write_frame(enc->format, pkt);
FFCHECK(ret, "av_interleaved_write_frame()");
}
av_packet_free(&pkt);
}
}
av_frame_free(&frame);
} else {
FFCHECK(ret, "avcodec_send_packet()");
}
} else if (packet->stream_index == dec->audioStream->index) {
// Deal with audio
}
av_packet_free(&packet);
}
ret = av_write_trailer(enc->format);
FFCHECK(ret, "av_write_trailer()");
ret = avio_close(enc->format->pb);
FFCHECK(ret, "avio_close()");
// Close some more stuff
return 0;
}
After thinking about this some more, I realised that I wasn't even sure if my decoder was correct. And another thorough inspection of the transcoding example revealed a small difference in behaviour.
Effectively, I was doing this:
while (true) {
ret = avcodec_send_packet(dec->videoCodec, packet);
if (ret != AVERROR(EAGAIN)) {
continue;
}
ret = avcodec_receive_frame(dec->videoCodec, frame);
}
Removing the continue and immediately trying to receive frames from the decoder works much better, and fixed my issue.
while (true) {
ret = avcodec_send_packet(dec->videoCodec, packet);
if (ret != 0)
abort();
ret = avcodec_receive_frame(dec->videoCodec, frame);
}
I also had the same error in the encoding side so I've fixed it there too.

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]))

How to decode AAC using avcodec_decode_audio4?

I changed in my code avcodec_decode_audio3 to avcodec_decode_audio4 and added the frame handling. But now I cannot decode AAC frames anymore.
Why does avcodec_decode_audio4 return -22 (invalid argument)?
Following the answer below, does this have something to do with the parameters in AVContext that need to be set?
I had to use avcodec_decode_audio4 because I updated my ffmpeg and then got the following error:
[NULL # 0xb14f020] Custom get_buffer() for use withavcodec_decode_audio3() detected.
Overriding with avcodec_default_get_buffer
[NULL # 0xb14f020] Please port your application to avcodec_decode_audio4()
According to Buffer error in avcodec_decode_audio4() this is a regression, is there any other solution for this than going back to ffmpeg < 0.8 ?
The decoder using avcodec_decode_audio4:
AVCodec *codec;
AVCodecContext *avCtx;
AVFrame * decoded_frame = NULL;
uint8_t *outbuf = static_cast<uint8_t *>(malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE));
AVPacket avPacket;
main(){
av_register_all();
codec = avcodec_find_decoder(CODEC_ID_AAC);
//set parameters
avCtx = avcodec_alloc_context3(codec);
avCtx->channels = 1;
avCtx->sample_rate = 44100;
avCtx->bit_rate=16;
if (avcodec_open2(avCtx, codec, NULL) < 0) printf("Could not open codec\n");
av_init_packet(&avPacket);
//Main decoder loop
while(1)
my_frame_decoder();
return 0;
}
void my_frame_decoder() {
//get data
...
avPacket.size = numBytes;
avPacket.data = inputBytes;
int len;
while (avPacket.size > 0) {
int got_frame = 0;
if (!decoded_frame) {
if (!(decoded_frame = avcodec_alloc_frame())) {
printf("out of memory");
return;
}
} else {
avcodec_get_frame_defaults(decoded_frame);
}
//-------------------->> returns always -22
len = avcodec_decode_audio4(avCtx, decoded_frame, &got_frame, &avPacket);
//do something with the decoded frame
...
avPacket.size -= len;
avPacket.data += len;
}
return;
}
After hours of searching, i found out that the dec_ctx of the avcodec_decode_audio4 must be opened by a dec_codec initialised by av_find_best_stream()
1° av_find_best_stream(in_fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1,
&dec_codec, 0);<br>
2° dec_ctx = m_in_aud_strm->codec;<br>
3° av_opt_set_int(dec_ctx, "refcounted_frames", 1, 0);<br>
4° avcodec_open2(dec_ctx, dec_codec, NULL)<br>
.
.
.
5° avcodec_decode_audio4(dec_ctx, pFrame, &got_frame, &pkt);
I think the problem is the parameters set in your codec's context. Please refer to https://www.ffmpeg.org/doxygen/trunk/structAVCodecContext.html for setting the parameters, which has changed from avcodec_decode_audio3 to avcodec_decode_audio4.
No solution but a workaround is to go back to older builds. After testing various builds that work with avcodec_decode_audio3, I thought it might be useful for others to know that ffmpeg-0.10.14.tar.bz2 from https://ffmpeg.org/releases/ works.
<!-- language: c++ -->
#include <windows.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <fcntl.h>
#include <ctype.h>
#include <math.h>
#include <wctype.h>
#include <wchar.h>
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <locale.h>
#include <signal.h>
#include <limits.h>
#include <float.h>
#include <iso646.h>
#undef NDEBUG
#include <assert.h>
// Use avcodec_send_packet() and avcodec_receive_frame().
//sample code
while (av_read_frame (FormatContext, packet_ptr) >= 0)
{
/* some code */
if (packet_ptr->stream_index == audiostream)
{
assert(NULL == decoded_frame);
decoded_frame = av_frame_alloc();
ret = avcodec_send_packet(pCodecCtx, packet_ptr);
if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)
{
av_packet_unref (packet_ptr);
if (decoded_frame)
{
av_frame_unref(decoded_frame);
decoded_frame = NULL;
}
continue;
}
else
{
if (0 <= ret)
packet_ptr->size = 0;
ret = avcodec_receive_frame(pCodecCtx, decoded_frame);
if (ret >= 0)
got_frame = 1;
else
{
got_frame = 0;
if (decoded_frame)
{
av_frame_unref(decoded_frame);
decoded_frame = NULL;
}
av_packet_unref (packet_ptr);
continue;
}
}
if(AV_SAMPLE_FMT_FLTP == pCodecCtx->sample_fmt)//AAC sample format for Libav released 10-October-2020 (ffmpeg 4.3.1)
{
//now get the PCM data ready to play or save
int nb_samples = decoded_frame->nb_samples;
int channels = pCodecCtx->channels;
if(channels > 2) //for this small sample only 2 channels...
{
channels = 2;//it will convert multichannel media files to 2 channels, remember this...more code need to be modified
}
int outputBufferLen = nb_samples * channels * 2;
int size_out //the size of the PCM data as sizeof(char)
=outputBufferLen;
char * buf = malloc(size_out);
short *outputBuffer=(short *)buf;
int in_samples = decoded_frame->nb_samples;
int i=0;
float * inputChannel0 = (float *)decoded_frame->extended_data[0];
// Mono
if (pCodecCtx->channels==1)
{
for (i=0; i<in_samples; i++)
{
float sample = *inputChannel0++;
if (sample<-1.0f) sample=-1.0f;
else if (sample>1.0f) sample=1.0f;
outputBuffer[i] = (int16_t) (sample * 32767.0f);//largest positive int16_t
}
}
// Stereo
else
{
float * inputChannel1 = (float *)decoded_frame->extended_data[1];
for (i=0; i < in_samples; i++)
{
float sample = *inputChannel0++;
if (sample<-1.0f) sample=-1.0f;
else if (sample>1.0f) sample=1.0f;
float sample2 = *inputChannel1++;
if (sample2<-1.0f) sample2=-1.0f;
else if (sample2>1.0f) sample2=1.0f;
outputBuffer[i*2] = (int16_t) ((sample) * 32767.0f);
outputBuffer[i*2+1] = (int16_t) ((sample2) * 32767.0f);
}
}
//use buf and size_out here then free the buf
free(buf);
}
}
av_packet_unref (packet_ptr);
if (decoded_frame)
{
av_frame_unref(decoded_frame);
decoded_frame = NULL;
}
}
Hope it helps...

Basic OpenAL code to play a sound

I'm new using OpenAl library. I'm following the OpenAl programming guide but i can't find.
I have this code extracted from page 10 of the OpenAl programming guide but still have no sound. I use OSX Snow Leopard, i know OSX doesn't have ALUT defined.
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
using namespace std;
#define NUM_BUFFERS 3
#define BUFFER_SIZE 4096
int main(int argc, char **argv)
{
ALCdevice *dev;
ALCcontext *ctx;
struct stat statbuf;
Aluint buffer[NUM_BUFFERS];
Aluint source[NUM_SOURCES];
ALsizei size, freq;
ALenum format;
ALvoid *data;
// Initialization
dev = alcOpenDevice(NULL); // select the "preferred dev"
if (dev)
{
ctx = alcCreateContext(dev,NULL);
alcMakeContextCurrent(ctx);
}
// Check for EAX 2.0 support
// g_bEAX = alIsExtensionPresent("EAX2.0");
// Generate Buffers
alGetError(); // clear error code
alGenBuffers(NUM_BUFFERS, buffer);
if ((error = alGetError()) != AL_NO_ERROR)
{
DisplayALError("alGenBuffers :", error);
return 1;
}
// Load test.wav
loadWAVFile("sample.wav", &format, &data, &size, &freq, &loop);
if ((error = alGetError()) != AL_NO_ERROR)
{
DisplayALError("LoadWAVFile sample.wav : ", error);
alDeleteBuffers(NUM_BUFFERS, buffer);
return 1;
}
// Copy test.wav data into AL Buffer 0
alBufferData(buffer[0], format, data, size, freq);
if ((error = alGetError()) != AL_NO_ERROR)
{
DisplayALError("alBufferData buffer 0 : ", error);
alDeleteBuffers(NUM_BUFFERS, buffer);
return 1;
}
// Unload test.wav
unloadWAV(format, data, size, freq);
if ((error = alGetError()) != AL_NO_ERROR)
{
DisplayALError("UnloadWAV : ", error);
alDeleteBuffers(NUM_BUFFERS, buffer);
return 1;
}
// Generate Sources
alGenSources(1, source);
if ((error = alGetError()) != AL_NO_ERROR)
{
DisplayALError("alGenSources 1 : ", error);
return 1;
}
// Attach buffer 0 to source
alSourcei(source[0], AL_BUFFER, buffer[0]);
if ((error = alGetError()) != AL_NO_ERROR)
{
DisplayALError("alSourcei AL_BUFFER 0 : ", error);
}
// Exit
ctx = alcGetCurrentContext();
dev = alcGetContextsDevice(ctx);
alcMakeContextCurrent(NULL);
alcDestroyContext(ctx);
alcCloseDevice(dev);
return 0;
}
What things I missed to make this code work ???
What i'm doing wrong ???
Any advice could help, thanks.
You are not calling alSourcePlay(source[0]) to start the playback.

Resources