I want to do a audio trancode using ffmpeg library. Now i have out file but I can listen only noise .
The steps of my program are:
1) Open input file and decode in raw format using avcodec_decode_audio4
2) encode and save the raw format .
I don't Know where I wrong. This is my code.
/*
* File: newmain.c
* Author: antonello
*
* Created on 23 gennaio 2013, 11.24
*/
#include <stdio.h>
#include <stdlib.h>
#include <libavutil/samplefmt.h>
#include <libavutil/timestamp.h>
#include <libavformat/avformat.h>
#include <libavcodec/old_codec_ids.h>
static AVCodecContext *get_encoder(int sampleRate, int channels, int audioBitrate)
{
AVCodecContext *audioCodec;
AVCodec *codec;
//Set up audio encoder
codec = avcodec_find_encoder(CODEC_ID_AAC);
if (codec == NULL)
{
printf("avcodec_find_encoder: ERROR\n");
return NULL;
}
audioCodec = avcodec_alloc_context();
audioCodec->bit_rate = audioBitrate;
audioCodec->sample_fmt = AV_SAMPLE_FMT_S16P;
audioCodec->sample_rate = sampleRate;
audioCodec->channels = channels;
audioCodec->profile = FF_PROFILE_AAC_MAIN;
audioCodec->channel_layout=AV_CH_LAYOUT_MONO;
//audioCodec->time_base = (AVRational){1, sampleRate};
audioCodec->time_base.num = 1;
audioCodec->time_base.den = sampleRate;
audioCodec->codec_type = AVMEDIA_TYPE_AUDIO;
if (avcodec_open(audioCodec, codec) < 0)
{
printf("avcodec_open: ERROR\n");
return NULL;
}
return audioCodec;
}
int main(int argc, char** argv) {
AVFormatContext *aFormatCtx_decoder = NULL;
AVFormatContext *aFormatCtx_encoder = NULL;
int i, audioStream;
AVPacket packet_decoder;
AVPacket packet_encoder;
int got_frame=0;
int complete_decode=0;
int len;
AVFrame *decoded_frame = NULL;
AVCodecContext *aCodec_decoderCtx = NULL;
AVCodec *aCodec_decoder = NULL;
FILE *outfile;
//reding input file
avcodec_register_all();
//register all codecs
av_register_all();
//open file
if(avformat_open_input(&aFormatCtx_decoder, "sample.aac", NULL, NULL)!=0){
fprintf(stderr, "Could not open source file \n");
return -1; // Couldn't open file
}
// Retrieve stream information
if(avformat_find_stream_info(aFormatCtx_decoder, NULL)<0){
fprintf(stderr, "Couldn't find stream information \n");
return -1; // Couldn't find stream information
}
// Dump information about file onto standard error
//av_dump_format(aFormatCtx_decode, 0, argv[1], 0);
// Find the first audio stream
audioStream=-1;
for(i=0; i<aFormatCtx_decoder->nb_streams; i++) {
if(aFormatCtx_decoder->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO &&
audioStream < 0) {
audioStream=i;
}
}
if(audioStream==-1){
fprintf(stderr, "File haven't sudio stream \n");
return -1;
}
//get audio codec contex
aCodec_decoderCtx=aFormatCtx_decoder->streams[audioStream]->codec;
//get audio codec
aCodec_decoder = avcodec_find_decoder(aCodec_decoderCtx->codec_id);
aCodec_decoder->sample_fmts=AV_SAMPLE_FMT_S16P;
if(!aCodec_decoder) {
fprintf(stderr, "Unsupported codec!\n");
return -1;//Unsupported codec!
}
//open codec
// Open codec
if(avcodec_open2(aCodec_decoderCtx, aCodec_decoder, NULL)<0)
return -1; // Could not open codec
// allocate audio frame
decoded_frame = avcodec_alloc_frame();
if (!decoded_frame) {
fprintf(stderr, "Could not allocate audio frame\n");
return -1;//Could not allocate audio frame
}
aCodec_decoderCtx->bit_rate=12000;
aFormatCtx_encoder=get_encoder(8000,1,12000);
av_init_packet(&packet_encoder);
printf("param %d %d %d",aCodec_decoderCtx->sample_fmt,aCodec_decoderCtx->channels,aCodec_decoderCtx->bit_rate);
outfile = fopen("out.aac", "wb");
if (!outfile) {
printf(stderr, "Could not open outfile \n");
return -1;//Could not open outfile
}
while(av_read_frame(aFormatCtx_decoder, &packet_decoder)>=0) {
// decode frame
len = avcodec_decode_audio4(aCodec_decoderCtx, decoded_frame, &got_frame, &packet_decoder);
if (len < 0) {
fprintf(stderr, "Error while decoding\n");
return -1;
}
if (got_frame){
avcodec_encode_audio2(aFormatCtx_encoder,&packet_encoder,decoded_frame,&complete_decode);
if(complete_decode){
// printf("complete decode frame");
fwrite(packet_encoder.data, 1, packet_encoder.size, outfile);
av_free_packet(&packet_encoder);
}
}
}
fclose(outfile);
return (EXIT_SUCCESS);
}
use the following code for sample format conversion.
you can get example in ffmpeg/doc/examples/resampling_audio.c
SwrContext *swr = swr_alloc();
av_opt_set_int(node_handle->swr, "in_channel_layout", decoded_frame->channel_layout, 0);
av_opt_set_int(node_handle->swr, "out_channel_layout", encoder_ctx->channel_layout, 0);
av_opt_set_int(node_handle->swr, "in_sample_rate", decoded_frame->sample_rate, 0);
av_opt_set_int(node_handle->swr, "out_sample_rate", encoder_ctx->sample_rate, 0);
av_opt_set_sample_fmt(swr, "in_sample_fmt", decoded_frame->format, 0);
av_opt_set_sample_fmt(swr, "out_sample_fmt", encoder_ctx->sample_fmt, 0);
swr_init(swr);
uint8_t* swr_out_data;
int linesize;
av_samples_alloc(&swr_out_data,
linesize,
encoder_ctx->nb_channels,
decoded_frame->nb_samples,
encoder_ctx->sample_fmt,
0
);
swr_convert(swr,&swr_out_data, decoded_frame->nb_samples, decoded_frame->data, decoded_frame->nb_samples);
You can not set arbitrary value of of the variable sample_fmts:
aCodec_decoder->sample_fmts=AV_SAMPLE_FMT_S16P; // It's wrong
Decoding will always be performed with the parameters set by the codec.
You have to create SwrContext and perform format conversion to the target (SwrContext converts sample format, sample rate and channels layout)
modify to this, works fine
aCodec_decoder->sample_fmts=audioCodec->sample_fmt;
Related
I'm trying to write a program to read and play an audio file using FFmpeg and libao. I've been following the procedure outlined in the FFmpeg documentation for decoding audio using the new avcodec_send_packet and avcodec_receive_frame functions, but the examples I've been able to find are few and far between (the ones in the FFmpeg documentation either don't use libavformat or use the deprecated avcodec_decode_audio4). I've based a lot of my program off of the transcode_aac.c example (up to init_resampler) in the FFmpeg documentation, but that also uses the deprecated decoding function.
I believe I have the decoding part of the program working, but I need to resample the audio in order to convert it into an interleaved format to send to libao, for which I'm attempting to use libswresample. Whenever the program is run in its current state, it outputs (many times) "Error resampling: Output changed". The test file I've been using is just a YouTube rip that I had on hand. ffprobe reports the only stream as:
Stream #0:0(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 125 kb/s (default)
This is my first program with FFmpeg (and I'm still relatively new to C), so any advice on how to improve/fix other parts of the program would be welcome.
#include<stdio.h>
#include<libavcodec/avcodec.h>
#include<libavformat/avformat.h>
#include<libavutil/avutil.h>
#include<libswresample/swresample.h>
#include<ao/ao.h>
#define OUTPUT_CHANNELS 2
#define OUTPUT_RATE 44100
#define BUFFER_SIZE 192000
#define OUTPUT_BITS 16
#define OUTPUT_FMT AV_SAMPLE_FMT_S16
static char *errtext (int err) {
static char errbuff[256];
av_strerror(err,errbuff,sizeof(errbuff));
return errbuff;
}
static int open_audio_file (const char *filename, AVFormatContext **context, AVCodecContext **codec_context) {
AVCodecContext *avctx;
AVCodec *codec;
int ret;
int stream_id;
int i;
// Open input file
if ((ret = avformat_open_input(context,filename,NULL,NULL)) < 0) {
fprintf(stderr,"Error opening input file '%s': %s\n",filename,errtext(ret));
*context = NULL;
return ret;
}
// Get stream info
if ((ret = avformat_find_stream_info(*context,NULL)) < 0) {
fprintf(stderr,"Unable to find stream info: %s\n",errtext(ret));
avformat_close_input(context);
return ret;
}
// Find the best stream
if ((stream_id = av_find_best_stream(*context,AVMEDIA_TYPE_AUDIO,-1,-1,&codec,0)) < 0) {
fprintf(stderr,"Unable to find valid audio stream: %s\n",errtext(stream_id));
avformat_close_input(context);
return stream_id;
}
// Allocate a decoding context
if (!(avctx = avcodec_alloc_context3(codec))) {
fprintf(stderr,"Unable to allocate decoder context\n");
avformat_close_input(context);
return AVERROR(ENOMEM);
}
// Initialize stream parameters
if ((ret = avcodec_parameters_to_context(avctx,(*context)->streams[stream_id]->codecpar)) < 0) {
fprintf(stderr,"Unable to get stream parameters: %s\n",errtext(ret));
avformat_close_input(context);
avcodec_free_context(&avctx);
return ret;
}
// Open the decoder
if ((ret = avcodec_open2(avctx,codec,NULL)) < 0) {
fprintf(stderr,"Could not open codec: %s\n",errtext(ret));
avformat_close_input(context);
avcodec_free_context(&avctx);
return ret;
}
*codec_context = avctx;
return 0;
}
static void init_packet (AVPacket *packet) {
av_init_packet(packet);
packet->data = NULL;
packet->size = 0;
}
static int init_resampler (AVCodecContext *codec_context, SwrContext **resample_context) {
int ret;
// Set resampler options
*resample_context = swr_alloc_set_opts(NULL,
av_get_default_channel_layout(OUTPUT_CHANNELS),
OUTPUT_FMT,
codec_context->sample_rate,
av_get_default_channel_layout(codec_context->channels),
codec_context->sample_fmt,
codec_context->sample_rate,
0,NULL);
if (!(*resample_context)) {
fprintf(stderr,"Unable to allocate resampler context\n");
return AVERROR(ENOMEM);
}
// Open the resampler
if ((ret = swr_init(*resample_context)) < 0) {
fprintf(stderr,"Unable to open resampler context: %s\n",errtext(ret));
swr_free(resample_context);
return ret;
}
return 0;
}
static int init_frame (AVFrame **frame) {
if (!(*frame = av_frame_alloc())) {
fprintf(stderr,"Could not allocate frame\n");
return AVERROR(ENOMEM);
}
return 0;
}
int main (int argc, char *argv[]) {
AVFormatContext *context = 0;
AVCodecContext *codec_context;
SwrContext *resample_context = NULL;
AVPacket packet;
AVFrame *frame = 0;
AVFrame *resampled = 0;
int16_t *buffer;
int ret, packet_ret, finished;
ao_device *device;
ao_sample_format format;
int default_driver;
if (argc != 2) {
fprintf(stderr,"Usage: %s <filename>\n",argv[0]);
return 1;
}
av_register_all();
printf("Opening file...\n");
if (open_audio_file(argv[1],&context,&codec_context) < 0)
return 1;
printf("Initializing resampler...\n");
if (init_resampler(codec_context,&resample_context) < 0) {
avformat_close_input(&context);
avcodec_free_context(&codec_context);
return 1;
}
// Setup libao
printf("Starting audio device...\n");
ao_initialize();
default_driver = ao_default_driver_id();
format.bits = OUTPUT_BITS;
format.channels = OUTPUT_CHANNELS;
format.rate = codec_context->sample_rate;
format.byte_format = AO_FMT_NATIVE;
format.matrix = 0;
if ((device = ao_open_live(default_driver,&format,NULL)) == NULL) {
fprintf(stderr,"Error opening audio device\n");
avformat_close_input(&context);
avcodec_free_context(&codec_context);
swr_free(&resample_context);
return 1;
}
// Mainloop
printf("Beginning mainloop...\n");
init_packet(&packet);
// Read packets until done
while (1) {
packet_ret = av_read_frame(context,&packet);
// Send a packet
if ((ret = avcodec_send_packet(codec_context,&packet)) < 0)
fprintf(stderr,"Error sending packet to decoder: %s\n",errtext(ret));
av_packet_unref(&packet);
while (1) {
if (!frame)
frame = av_frame_alloc();
ret = avcodec_receive_frame(codec_context,frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) // Need more input
break;
else if (ret < 0) {
fprintf(stderr,"Error receiving frame: %s\n",errtext(ret));
break;
}
// We have a valid frame, need to resample it
if (!resampled)
resampled = av_frame_alloc();
resampled->channel_layout = av_get_default_channel_layout(OUTPUT_CHANNELS);
resampled->sample_rate = codec_context->sample_rate;
resampled->format = OUTPUT_FMT;
if ((ret = swr_convert_frame(resample_context,resampled,frame)) < 0) {
fprintf(stderr,"Error resampling: %s\n",errtext(ret));
} else {
ao_play(device,(char*)resampled->extended_data[0],resampled->linesize[0]);
}
av_frame_unref(resampled);
av_frame_unref(frame);
}
if (packet_ret == AVERROR_EOF)
break;
}
printf("Closing file and freeing contexts...\n");
avformat_close_input(&context);
avcodec_free_context(&codec_context);
swr_free(&resample_context);
printf("Closing audio device...\n");
ao_close(device);
ao_shutdown();
return 0;
}
UPDATE: I've got it playing sound now, but it sounds like samples are missing (and MP3 files warn that "Could not update timestamps for skipped samples"). The issue was that the resampled frame needed to have certain attributes set before being passed to swr_convert_frame. I've also added av_packet_unref and av_frame_unref, but I'm still unsure as to where to best locate them.
ao_play(device,(char*)resampled->extended_data[0],resampled->linesize[0]);
You have problem in this line. Resampled audio frame has incorrect linesize parameters. swr_convert_frame aligns data and extended_data fields with silence. This silence is included into linesize parameter so you pass incorrect frame size into ao_play function.
ao_play(device, (char*)resampled->extended_data[0], av_sample_get_buffer_size(resampled->linesize, resampled->channels, resampled->nb_samples, resampled->format, 0));
Function av_sample_get_buffer_size() returns true sample size, without align. When I faced similar problem, this was the solution.
i have been trying to decode an MP3 file to pcm, using ffmpeg API, but i keep getting an error
[mp3 # 0x8553020]Header missing
this is the code i use :
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef HAVE_AV_CONFIG_H
#undef HAVE_AV_CONFIG_H
#endif
#include "libavcodec/avcodec.h"
#include "libavutil/mathematics.h"
#define INBUF_SIZE 4096
#define AUDIO_INBUF_SIZE 20480
#define AUDIO_REFILL_THRESH 4096
static void audio_decode_example(const char *outfilename, const char *filename)
{
AVCodec *codec;
AVCodecContext *c= NULL;
int out_size, len;
FILE *f, *outfile;
uint8_t *outbuf;
uint8_t inbuf[AUDIO_INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
AVPacket avpkt;
av_init_packet(&avpkt);
printf("Audio decoding\n");
/* find the mpeg audio decoder */
codec = avcodec_find_decoder(CODEC_ID_MP3ON4);
if (!codec) {
fprintf(stderr, "codec not found\n");
exit(1);
}
c= avcodec_alloc_context();
/* open it */
if (avcodec_open(c, codec) < 0) {
fprintf(stderr, "could not open codec\n");
exit(1);
}
outbuf = malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
f = fopen(filename, "rb");
if (!f) {
fprintf(stderr, "could not open %s\n", filename);
exit(1);
}
outfile = fopen(outfilename, "wb");
if (!outfile) {
av_free(c);
exit(1);
}
/* decode until eof */
avpkt.data = inbuf;
avpkt.size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f);
while (avpkt.size > 0) {
out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
len = avcodec_decode_audio3(c, (short *)outbuf, &out_size, &avpkt);
if (len < 0) {
fprintf(stderr, "Error while decoding\n");
exit(1);
}
if (out_size > 0) {
/* if a frame has been decoded, output it */
fwrite(outbuf, 1, out_size, outfile);
}
avpkt.size -= len;
avpkt.data += len;
if (avpkt.size < AUDIO_REFILL_THRESH) {
/* Refill the input buffer, to avoid trying to decode
* incomplete frames. Instead of this, one could also use
* a parser, or use a proper container format through
* libavformat. */
memmove(inbuf, avpkt.data, avpkt.size);
avpkt.data = inbuf;
len = fread(avpkt.data + avpkt.size, 1,
AUDIO_INBUF_SIZE - avpkt.size, f);
if (len > 0)
avpkt.size += len;
}
}
fclose(outfile);
fclose(f);
free(outbuf);
avcodec_close(c);
av_free(c);
}
int main(int argc, char **argv)
{
const char *filename;
/* must be called before using avcodec lib */
avcodec_init();
/* register all the codecs */
avcodec_register_all();
audio_decode_example("test.wav", argv[1]);
return 0;
}
when i use the same code to directly play the sound, like this :
if (out_size > 0) {
/* if a frame has been decoded, output it *
play_sound(outbuf, out_size);
}
i have no problem at all with some files, other mp3 files just gives an error without even starting ... is there any ideas ?
PS: this code is from libavcodec/api-example.c , modified as needed
I think i found my answer, the avpkt.data must have a header in front, without any garbage or previous frame bytes, or may be initial mp3 file data (name, gender, year ... etc).
so a little parser must be wrote, this is a useful link for mp3 headers (just search for the correct bytes in within the file, and increase avpkt.data pointer to match):
http://www.mp3-tech.org/programmer/frame_header.html
Use avformat for reading instead of fread(). For example, it can be customized (e.g. for buffering), it can detect and check formats automatically on opening and also has separated probe functions and other format-related stuff. And it works properly with headers. I came to following usage (warning, code can contain errors)
struct FormatCtx {
inline FormatCtx(const char* filename)
: ctx_(avformat_alloc_context()) {
av_init_packet(&p);
if (avformat_open_input(&ctx_, filename, 0, 0) < 0)
abort();
if (avformat_find_stream_info(ctx_, 0) < 0)
abort();
}
inline ~FormatCtx() {
av_free_packet(&p);
}
inline bool read() {
return av_read_frame(ctx_, &p) >= 0;
}
AVFormatContext* ctx_;
AVPacket p;
} formatCtx_;
AVCodec* findCodec(const char* filename) {
AVCodec* codec = formatCtx_.ctx_->audio_codec;
if (codec)
return codec;
codec = avcodec_find_decoder(formatCtx_.ctx_->audio_codec_id);
if (codec)
return codec;
AVOutputFormat* fmt = av_guess_format(0, //const char *short_name,
filename, 0); // const char *mime_type);;
codec = fmt ? avcodec_find_decoder(fmt->audio_codec) : 0;
if (codec)
return codec;
return 0;
}
//*** initialize all stuff ***
AVCodec* codec = findCodec(filename);
if (!codec)
exit(1);
AVCodecContext* c; // class member for me, needed for following reading
int stream_index_; // class member for me, needed for extra stuff
for (size_t i = 0; i < formatCtx_.ctx_->nb_streams; ++i) {
AVCodecContext* tc = formatCtx_.ctx_->streams[i]->codec;
if (tc->codec_type == AVMEDIA_TYPE_AUDIO) {
c = tc;
stream_index_ = i;
break;
}
}
// for example, here we're know track length
l->onDurationDetected(double(formatCtx_.ctx_->streams[stream_index_]->duration)
* av_q2d(formatCtx_.ctx_->streams[stream_index_]->time_base));
if (avcodec_open2(c, codec, &d.d_) < 0)
exit(1);
c->channels = 2;
c->sample_rate = 48000;
c->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
c->channel_layout = av_get_default_channel_layout(2);
After that you should basically prepare decoded_frame from TC's example and pass packet used for reading to avcodec_decode_audio4 (instead of avpkt).
I'm trying to decode AAC in RTP packet with FFmpeg. According to rfc document the RTP payload is audioMuxElement mapped directly. I try remove the RTP header and read the remaining bytes to AVPacket struct, but the avcodec_decode_audio4() returning error -1094995529. Here is the code:
#include "stdafx.h"
#include "stdio.h"
#include "conio.h"
extern "C"
{
#ifndef __STDC_CONSTANT_MACROS
#define __STDC_CONSTANT_MACROS
#endif
#include <libavcodec\avcodec.h>
#include <libavformat\avformat.h>
}
// compatibility with newer API
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1)
#define av_frame_alloc avcodec_alloc_frame
#define av_frame_free avcodec_free_frame
#endif
#define AUDIO_INBUF_SIZE 20480
#define AUDIO_REFILL_THRESH 4096
#define SAMPLE_RATE 44100
#define CHANNEL_NUM 2
static void decode_packet();
int main(int argc, char *argv[]) {
decode_packet();
getch();
return 0;
}
static void decode_packet()
{
const char *filename = "D:\\NoRTP_AACPacket.dat";
const char *outfilename = "D:\\test2.pcm";
AVCodec *codec;
AVFormatContext *pFormatCtx = NULL;
AVCodecContext * pCodecCtx= NULL;
int len;
FILE *f, *outfile;
uint8_t inbuf[AUDIO_INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
AVPacket avpkt;
AVFrame *decoded_frame = NULL;
av_register_all();
av_init_packet(&avpkt);
printf("Decode audio file %s to %s\n", filename, outfilename);
// Find the decoder for the audio stream
codec=avcodec_find_decoder(AV_CODEC_ID_AAC_LATM);
if(codec==NULL) {
fprintf(stderr, "Codec not found\n");
return; // Codec not found
}
pCodecCtx = avcodec_alloc_context3(codec);
if (!pCodecCtx) {
fprintf(stderr, "Could not allocate audio codec context\n");
return;
}
pCodecCtx->sample_rate = SAMPLE_RATE;
pCodecCtx->channels = CHANNEL_NUM;
/* open it */
if (avcodec_open2(pCodecCtx, codec, NULL) < 0) {
fprintf(stderr, "Could not open codec\n");
return;
}
f = fopen(filename, "rb");
if (!f) {
fprintf(stderr, "Could not open %s\n", filename);
return;
}
outfile = fopen(outfilename, "wb");
if (!outfile) {
av_free(pCodecCtx);
return;
}
avpkt.data = inbuf;
avpkt.size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f);
// supposed to do this but don't have AVFormatContext
// int frReadStt = av_read_frame(pFormatCtx, &avpkt);
/* decode until eof */
while (avpkt.size > 0) {
int i, ch;
int got_frame = 0;
if (!decoded_frame) {
if (!(decoded_frame = av_frame_alloc())) {
fprintf(stderr, "Could not allocate audio frame\n");
return;
}
}
len = avcodec_decode_audio4(pCodecCtx, decoded_frame, &got_frame, &avpkt);
if (len < 0) {
fprintf(stderr, "Error while decoding. len = %d \n",len);
return;
}
if (got_frame) {
/* if a frame has been decoded, output it */
int data_size = av_get_bytes_per_sample(pCodecCtx->sample_fmt);
if (data_size < 0) {
/* This should not occur, checking just for paranoia */
fprintf(stderr, "Failed to calculate data size\n");
return;
}
for (i=0; i < decoded_frame->nb_samples; i++)
for (ch=0; ch < pCodecCtx->channels; ch++)
fwrite(decoded_frame->data[ch] + data_size*i, 1, data_size, outfile);
}
avpkt.size -= len;
avpkt.data += len;
avpkt.dts =
avpkt.pts = AV_NOPTS_VALUE;
// frReadStt = av_read_frame(pFormatCtx, &avpkt);
if (avpkt.size < AUDIO_REFILL_THRESH) {
/* Refill the input buffer, to avoid trying to decode
* incomplete frames. Instead of this, one could also use
* a parser, or use a proper container format through
* libavformat. */
memmove(inbuf, avpkt.data, avpkt.size);
avpkt.data = inbuf;
len = fread(avpkt.data + avpkt.size, 1,
AUDIO_INBUF_SIZE - avpkt.size, f);
if (len > 0)
avpkt.size += len;
}
}
fclose(outfile);
fclose(f);
avcodec_close(pCodecCtx);
av_free(pCodecCtx);
av_frame_free(&decoded_frame);
printf("Finish decode audio file %s to %s\n", filename, outfilename);
}
I learnt from this question that I should use av_read_frame() instead of fread but I only have RTP payload not a whole file. Is it right to directly map rtp payload to AVPacket struct? If not then how should I decode the RTP payload?
I ended up using codec AV_CODEC_ID_AAC instead of AV_CODEC_ID_AAC_LATM. After digging into rfc and ISO document, I figured out that the packet is format in LATM but the input packet for AAC Decoder have to be formatted in ADTS, so a bit of parser have to be written here. I can't post the code but it's not too hard to write one.
I'm trying to decode AAC with FFmpeg native decoder and encountered an error
SSR is not implemeted. Update your FFmpeg version to newest from Git. If the problem still occurs, it mean that your file has a feature which has not implemented.
Function avcodec_decode_audio4() return -1163346256. Is this because of FFmpeg version? I downloaded shared and dev version from here. Is this up to date?
Here is the source code:
#include "stdafx.h"
#include "stdio.h"
#include "conio.h"
extern "C"
{
#ifndef __STDC_CONSTANT_MACROS
#define __STDC_CONSTANT_MACROS
#endif
#include <libavcodec\avcodec.h>
#include <libavformat/avformat.h>
}
// compatibility with newer API
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1)
#define av_frame_alloc avcodec_alloc_frame
#define av_frame_free avcodec_free_frame
#endif
#define AUDIO_INBUF_SIZE 20480
#define AUDIO_REFILL_THRESH 4096
static void audio_decode_example(const char *outfilename, const char *filename);
int main(int argc, char *argv[]) {
audio_decode_example("D:\\sample.pcm","D:\\sample.m4a");
getch();
return 0;
}
/*
* Audio decoding.
*/
static void audio_decode_example(const char *outfilename, const char *filename)
{
AVCodec *codec;
AVFormatContext *pFormatCtx = NULL;
AVCodecContext *pCodecCtxOrig = NULL;
AVCodecContext * pCodecCtx= NULL;
int len;
FILE *f, *outfile;
uint8_t inbuf[AUDIO_INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
AVPacket avpkt;
AVFrame *decoded_frame = NULL;
av_register_all();
av_init_packet(&avpkt);
printf("Decode audio file %s to %s\n", filename, outfilename);
// Open file to get format context
if(avformat_open_input(&pFormatCtx, filename, NULL, NULL)!=0){
printf("Couldn't open file");
return; // Couldn't open file
}
// Retrieve stream information
if(avformat_find_stream_info(pFormatCtx, NULL)<0){
printf("Couldn't find stream information");
return; // Couldn't find stream information
}
// Dump information about file onto standard error
av_dump_format(pFormatCtx, 0, filename, 0);
// Find the first audio stream
int audioStream = -1;
int i =0;
for(i=0; i<pFormatCtx->nb_streams; i++) {
if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO) {
audioStream=i;
break;
}
}
if(audioStream==-1) {
printf("Didn't find a audio stream");
return; // Didn't find a audio stream
}
// Get a pointer to the codec context for the audio stream
pCodecCtxOrig=pFormatCtx->streams[audioStream]->codec;
// Find the decoder for the audio stream
codec=avcodec_find_decoder(pCodecCtxOrig->codec_id);
if(codec==NULL) {
fprintf(stderr, "Codec not found\n");
return; // Codec not found
}
pCodecCtx = avcodec_alloc_context3(codec);
if (!pCodecCtx) {
fprintf(stderr, "Could not allocate audio codec context\n");
return;
}
if(avcodec_copy_context(pCodecCtx, pCodecCtxOrig) != 0) {
fprintf(stderr, "Couldn't copy codec context");
return; // Error copying codec context
}
/* open it */
if (avcodec_open2(pCodecCtx, codec, NULL) < 0) {
fprintf(stderr, "Could not open codec\n");
return;
}
f = fopen(filename, "rb");
if (!f) {
fprintf(stderr, "Could not open %s\n", filename);
return;
}
outfile = fopen(outfilename, "wb");
if (!outfile) {
av_free(pCodecCtx);
return;
}
/* decode until eof */
avpkt.data = inbuf;
avpkt.size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f);
while (avpkt.size > 0) {
int i, ch;
int got_frame = 0;
if (!decoded_frame) {
if (!(decoded_frame = av_frame_alloc())) {
fprintf(stderr, "Could not allocate audio frame\n");
return;
}
}
len = avcodec_decode_audio4(pCodecCtx, decoded_frame, &got_frame, &avpkt);
if (len < 0) {
fprintf(stderr, "Error while decoding. len = %d \n",len);
return;
}
if (got_frame) {
/* if a frame has been decoded, output it */
int data_size = av_get_bytes_per_sample(pCodecCtx->sample_fmt);
if (data_size < 0) {
/* This should not occur, checking just for paranoia */
fprintf(stderr, "Failed to calculate data size\n");
return;
}
for (i=0; i < decoded_frame->nb_samples; i++)
for (ch=0; ch < pCodecCtx->channels; ch++)
fwrite(decoded_frame->data[ch] + data_size*i, 1, data_size, outfile);
}
avpkt.size -= len;
avpkt.data += len;
avpkt.dts =
avpkt.pts = AV_NOPTS_VALUE;
if (avpkt.size < AUDIO_REFILL_THRESH) {
/* Refill the input buffer, to avoid trying to decode
* incomplete frames. Instead of this, one could also use
* a parser, or use a proper container format through
* libavformat. */
memmove(inbuf, avpkt.data, avpkt.size);
avpkt.data = inbuf;
len = fread(avpkt.data + avpkt.size, 1,
AUDIO_INBUF_SIZE - avpkt.size, f);
if (len > 0)
avpkt.size += len;
}
}
fclose(outfile);
fclose(f);
avcodec_close(pCodecCtx);
av_free(pCodecCtx);
av_frame_free(&decoded_frame);
}
I have also read this question: How to decode AAC using avcodec_decode_audio4? but no solution is provided.
f = fopen(filename, "rb");
if (!f) {
fprintf(stderr, "Could not open %s\n", filename);
return;
}
outfile = fopen(outfilename, "wb");
if (!outfile) {
av_free(pCodecCtx);
return;
}
/* decode until eof */
avpkt.data = inbuf;
avpkt.size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f);
while (avpkt.size > 0) {
int i, ch;
int got_frame = 0;
Yeah, that's not going to work. You can't dump raw bytes from some random muxing format (potentially mp4) into a decoder and expect it to work. Use av_read_frame() to read individual audio packets from the muxing format, and feed the resulting AVPacket into the decoder using avcodec_decode_audio4(). See e.g. the dranger api tutorial. I know api-example.c uses the above code, but that unfortunately only works for a very limited subset of cases. Also see the detailed description in the API docs.
I'm trying to write a C program using LibAV that takes input video from a webcam and saves it as an H264 MP4 file. I'm modifying a working program that saves .ppm frames from the webcam. I'm unable to convert the AVPackets so that they may be written, though--specifically, avformat_write_header() is failing, with the messages
[mp4 # 0050c000] Codec for stream 0 does not use global headers but container format requires global headers
[mp4 # 0050c000] Could not find tag for codec none in stream #0, codec not currently supported in container
The call is apparently returning error -22, but I can find no place where that error code is actually explained. How can I force avformat_write_header() to add in global headers when it's trying to write the MP4? Code below; some of it is adapted from this question, but I'm trying to adapt it from an input video file to a webcam.
int _tmain(int argc, _TCHAR* argv[])
{
AVInputFormat *inputFormat = NULL;
AVDictionary *inputDictionary= NULL;
AVFormatContext *inputFormatCtx = NULL;
AVFormatContext *outputFormatCtx = NULL;
AVCodecContext *inputCodecCtxOrig = NULL;
AVCodecContext *inputCodecCtx = NULL;
AVCodecContext *outputCodecCtx;
AVCodec *inputCodec = NULL;
AVCodec *outputCodec = NULL;
AVStream *stream = NULL;
AVIOContext *avioContext = NULL;
avcodec_register_all();
av_register_all();
avdevice_register_all();
av_dict_set(&inputDictionary, "Logitech HD Pro Webcam C920", "video", 0);
avformat_alloc_output_context2(&outputFormatCtx, NULL, NULL, "output.mp4");
avio_open(&avioContext, "output.mp4", AVIO_FLAG_WRITE);
outputFormatCtx->pb = avioContext;
stream = avformat_new_stream(outputFormatCtx, outputCodec);
inputFormat = av_find_input_format("dshow");
int r = avformat_open_input(&inputFormatCtx, "video=Logitech HD Pro Webcam C920", inputFormat, &inputDictionary);
if (r != 0) {
fprintf(stderr, "avformat_open_input() failed with error %d!\n", r);
return -1; }
r = avformat_find_stream_info(inputFormatCtx, NULL);
if (r != 0) {
fprintf(stderr, "avformat_find_stream_info() failed!\n");
return -1; }
av_dump_format(inputFormatCtx, 0, "video=Logitech HD Pro Webcam C920", 0);
unsigned int i;
int videoStream;
videoStream = -1;
for (i = 0; i < inputFormatCtx->nb_streams; i++) {
if (inputFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO {
videoStream = i;
break; }
}
if (videoStream == -1)
{ return -1; }
inputCodecCtxOrig = inputFormatCtx->streams[videoStream]->codec;
inputCodec = avcodec_find_decoder(inputCodecCtxOrig->codec_id);
if (inputCodec == NULL) {
fprintf(stderr, "avcodec_find_decoder() failed!\n");
return -1; }
else { printf("Supported codec!\n"); }
inputCodecCtx = avcodec_alloc_context3(inputCodec);
if (inputCodecCtx == NULL) {
fprintf(stderr, "avcodec_alloc_context3() failed!\n");
return -1; }
if (avcodec_copy_context(inputCodecCtx, inputCodecCtxOrig) != 0) {
fprintf(stderr, "avcodec_copy_context() failed!\n");
return -1; }
if (avcodec_open2(inputCodecCtx,inputCodec,&inputDictionary) < 0) {
fprintf(stderr, "avcodec_open2() failed!\n");
return -1; }
outputFormatCtx->oformat = av_guess_format(NULL, "output.mp4", NULL);
outputFormatCtx->oformat->flags |= AVFMT_GLOBALHEADER;
outputCodecCtx = avcodec_alloc_context3(outputCodec);
avcodec_copy_context(outputCodecCtx, inputCodecCtx);
outputCodec = inputCodec;
avcodec_open2(outputCodecCtx, outputCodec, NULL);
AVPacket packet;
printf("foo\n");
int errnum = avformat_write_header(outputFormatCtx, &inputDictionary);
printf("bar %d\n", errnum);
while(av_read_frame(inputFormatCtx, &packet)>=0) {
av_interleaved_write_frame(outputFormatCtx, &packet);
av_free_packet(&packet);
}
avcodec_close(inputCodecCtx);
avcodec_close(inputCodecCtxOrig);
avformat_close_input(&inputFormatCtx);
return 0;
}
How can I force avformat_write_header() to add in global headers
Global headers are written by the encoder, later the muxer reads them from the codec's extra_data field. So you should set this flag in the codec's context, before you call avcodec_open2().
outputCodecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
[mp4 # 0050c000] Could not find tag for codec none in stream #0, codec
not currently supported in container
You can try to setup the encoder explicitly (i.e. manually), or copy the codeccontext from original input codeccontext.
outputCodec = av_codec_find_encoder(AV_CODEC_ID_H264);
if(!outputCodec) return -1; //no encoder found
outputCodecCtx = avcodec_alloc_context3(outputCodec);
avcodec_copy_context(outputCodecCtx, inputCodecCtxOrig); //copy from orig
//You have to make sure each field is populated correctly
//with debugger or assertations
assert(outputCodecCtx->codec_id == AV_CODEC_ID_H264); //etc
outputCodecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
if(avcodec_open2(outputCodecCtx, outputCodec, NULL) <0) return -1;