Related
inspired by other stackoverflow answers, I wrote a code to get an rtps stream into an mp4 file. I tried commenting as much as possible:
#include <stdio.h>
#include <stdlib.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavformat/avio.h>
#include <sys/time.h>
time_t get_time()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec;
}
int main(int argc, char* argv[])
{
AVFormatContext* ifcx = NULL;
AVCodecContext* iccx;
AVStream* ist;
int i_index;
time_t timenow, timestart;
AVFormatContext* ofcx;
AVOutputFormat* ofmt;
AVStream* ost;
AVPacket pkt;
int ix;
const char* sProg = argv[0];
const char* sFileInput;
const char* sFileOutput;
int bRunTime;
if (argc != 4)
{
printf("Usage: %s url outfile runtime\n", sProg);
return EXIT_FAILURE;
}
sFileInput = argv[1];
sFileOutput = argv[2];
bRunTime = atoi(argv[3]);
// Initialize library
av_log_set_level(AV_LOG_ERROR);
avformat_network_init();
//
// Input
//
// open rtsp
AVDictionary* opts = 0;
av_dict_set(&opts, "rtsp_transport", "tcp", 0);
if (avformat_open_input(&ifcx, sFileInput, 0, &opts) != 0)
{
printf("ERROR: Cannot open input file\n");
return EXIT_FAILURE;
}
if (avformat_find_stream_info(ifcx, NULL) < 0)
{
printf("ERROR: Cannot find stream info\n");
avformat_close_input(&ifcx);
return EXIT_FAILURE;
}
snprintf(ifcx->url, sizeof(ifcx->url), "%s", sFileInput);
// search video stream
i_index = -1;
AVCodecParameters* iccx_par;
for (ix = 0; ix < ifcx->nb_streams; ix++)
{
iccx_par = ifcx->streams[ix]->codecpar;
if (iccx_par->codec_type == AVMEDIA_TYPE_VIDEO)
{
ist = ifcx->streams[ix];
i_index = ix;
break;
}
}
if (i_index < 0)
{
printf("ERROR: Cannot find input video stream\n");
avformat_close_input(&ifcx);
return EXIT_FAILURE;
}
// Allocate codec context and convert codec parameters to codec context
iccx = avcodec_alloc_context3(NULL);
avcodec_parameters_to_context(iccx, iccx_par);
// set output format
ofmt = av_guess_format("mp4", NULL, NULL);
// create output context
if (avformat_alloc_output_context2(&ofcx, ofmt, NULL, sFileOutput) < 0)
{
printf("ERROR: Cannot create output context\n");
avformat_close_input(&ifcx);
return EXIT_FAILURE;
}
// add video stream
ost = avformat_new_stream(ofcx, NULL);
if (!ost)
{
printf("ERROR: Cannot add output stream\n");
avformat_close_input(&ifcx);
avformat_free_context(ofcx);
return EXIT_FAILURE;
}
// copy codec context
if (avcodec_parameters_from_context(ost->codecpar, iccx) < 0)
{
printf("ERROR: Cannot copy codec context\n");
avformat_close_input(&ifcx);
avformat_free_context(ofcx);
return EXIT_FAILURE;
}
// open output file
if (!(ofmt->flags & AVFMT_NOFILE))
{
if (avio_open(&ofcx->pb, sFileOutput, AVIO_FLAG_WRITE) < 0)
{
printf("ERROR: Cannot open output file\n");
avformat_close_input(&ifcx);
avformat_free_context(ofcx);
return EXIT_FAILURE;
}
}
// write output file header
if (avformat_write_header(ofcx, NULL) < 0)
{
printf("ERROR: Cannot write output file header\n");
avformat_close_input(&ifcx);
avio_close(ofcx->pb);
avformat_free_context(ofcx);
return EXIT_FAILURE;
}
//
// Write data
//
AVRational time_base = ist->time_base;
timestart = get_time();
int64_t pts = 0;
while (av_read_frame(ifcx, &pkt) >= 0)
{
if (get_time() - timestart > bRunTime)
{
break;
}
if (pkt.stream_index == i_index)
{
pkt.stream_index = ost->id;
pkt.pts = pkt.duration * pts;
pkt.dts = pkt.pts;
if (av_interleaved_write_frame(ofcx, &pkt) < 0)
{
printf("ERROR: Cannot write packet\n");
av_packet_unref(&pkt);
break;
}
pts++;
}
}
// write output file trailer
if (av_write_trailer(ofcx) < 0)
{
printf("ERROR: Cannot write output file trailer\n");
}
//
// Close
//
avformat_close_input(&ifcx);
avio_close(ofcx->pb);
avformat_free_context(ofcx);
avformat_network_deinit();
return EXIT_SUCCESS;
}
Compile:
gcc test.c -Wunused-variable -lavcodec -lavformat -lavfilter -lavdevice -lswresample -lswscale -lavutil -o a.out
Run:
./a.out rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mp4 out.mp4 5
Then using ffprobe, the video will last different time every time:
5.875000
6.500000
If i run the CLI
ffmpeg -t 5 -i rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mp4 -vcodec copy -acodec copy -map 0 -f mp4 out.mp4
It will always give 5.124000
What am I doing wrong?
Thanks!
I created a .sw(16 bit pcm) file by passing an audio file. Now I am trying to get back the original audio(.mp3) by passing the .sw file as an input to the following file.
How can I read the .sw file content so that I can get back the mp3 file. Below is the code,
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/channel_layout.h>
#include <libavutil/common.h>
#include <libavutil/frame.h>
#include <libavutil/samplefmt.h>
/* check that a given sample format is supported by the encoder */
static int check_sample_fmt(const AVCodec *codec, enum AVSampleFormat sample_fmt)
{
const enum AVSampleFormat *p = codec->sample_fmts;
while (*p != AV_SAMPLE_FMT_NONE) {
if (*p == sample_fmt)
return 1;
p++;
}
return 0;
}
/* just pick the highest supported samplerate */
static int select_sample_rate(const AVCodec *codec)
{
const int *p;
int best_samplerate = 0;
if (!codec->supported_samplerates)
return 44100;
p = codec->supported_samplerates;
while (*p) {
if (!best_samplerate || abs(44100 - *p) < abs(44100 - best_samplerate))
best_samplerate = *p;
p++;
}
return best_samplerate;
}
/* select layout with the highest channel count */
static int select_channel_layout(const AVCodec *codec)
{
const uint64_t *p;
uint64_t best_ch_layout = 0;
int best_nb_channels = 0;
if (!codec->channel_layouts)
return AV_CH_LAYOUT_STEREO;
p = codec->channel_layouts;
while (*p) {
int nb_channels = av_get_channel_layout_nb_channels(*p);
if (nb_channels > best_nb_channels) {
best_ch_layout = *p;
best_nb_channels = nb_channels;
}
p++;
}
return best_ch_layout;
}
static void encode(AVCodecContext *ctx, AVFrame *frame, AVPacket *pkt,
FILE *output)
{
int ret;
/* send the frame for encoding */
ret = avcodec_send_frame(ctx, frame);
if (ret < 0) {
fprintf(stderr, "Error sending the frame to the encoder\n");
exit(1);
}
/* read all the available output packets (in general there may be any
* number of them */
while (ret >= 0) {
ret = avcodec_receive_packet(ctx, pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
return;
else if (ret < 0) {
fprintf(stderr, "Error encoding audio frame\n");
exit(1);
}
fwrite(pkt->data, 1, pkt->size, output);
av_packet_unref(pkt);
}
}
int main(int argc, char **argv)
{
const char *filename;
const AVCodec *codec;
AVCodecContext *c= NULL;
AVFrame *frame;
AVPacket *pkt;
int i, j, k, ret;
FILE *f;
uint16_t *samples;
float t, tincr;
av_register_all();
avcodec_register_all();
if (argc <= 1) {
fprintf(stderr, "Usage: %s <output file>\n", argv[0]);
return 0;
}
filename = argv[1];
/* find the MP2 encoder */
codec = avcodec_find_encoder(AV_CODEC_ID_MP3);
if (!codec) {
fprintf(stderr, "Codec not found\n");
exit(1);
}
c = avcodec_alloc_context3(codec);
if (!c) {
fprintf(stderr, "Could not allocate audio codec context\n");
exit(1);
}
/* put sample parameters */
c->bit_rate = 64000;
/* check that the encoder supports s16 pcm input */
c->sample_fmt = AV_SAMPLE_FMT_S16P;
if (!check_sample_fmt(codec, c->sample_fmt)) {
fprintf(stderr, "Encoder does not support sample format %s",
av_get_sample_fmt_name(c->sample_fmt));
exit(1);
}
/* select other audio parameters supported by the encoder */
c->sample_rate = select_sample_rate(codec);
c->channel_layout = select_channel_layout(codec);
c->channels = av_get_channel_layout_nb_channels(c->channel_layout);
/* open it */
if (avcodec_open2(c, codec, NULL) < 0) {
fprintf(stderr, "Could not open codec\n");
exit(1);
}
f = fopen(filename, "wb");
if (!f) {
fprintf(stderr, "Could not open %s\n", filename);
exit(1);
}
/* packet for holding encoded output */
pkt = av_packet_alloc();
if (!pkt) {
fprintf(stderr, "could not allocate the packet\n");
exit(1);
}
/* frame containing input raw audio */
frame = av_frame_alloc();
if (!frame) {
fprintf(stderr, "Could not allocate audio frame\n");
exit(1);
}
frame->nb_samples = c->frame_size;
frame->format = c->sample_fmt;
frame->channel_layout = c->channel_layout;
/* allocate the data buffers */
ret = av_frame_get_buffer(frame, 0);
if (ret < 0) {
fprintf(stderr, "Could not allocate audio data buffers\n");
exit(1);
}
/* encode a single tone sound */
t = 0;
tincr = 2 * M_PI * 440.0 / c->sample_rate;
for (i = 0; i < 200; i++) {
/* make sure the frame is writable -- makes a copy if the encoder
* kept a reference internally */
ret = av_frame_make_writable(frame);
if (ret < 0)
exit(1);
samples = (uint16_t*)frame->data[0];
for (j = 0; j < c->frame_size; j++) {
samples[2*j] = (int)(sin(t) * 10000);
for (k = 1; k < c->channels; k++)
samples[2*j + k] = samples[2*j];
t += tincr;
}
encode(c, frame, pkt, f);
}
/* flush the encoder */
encode(c, NULL, pkt, f);
fclose(f);
av_frame_free(&frame);
av_packet_free(&pkt);
avcodec_free_context(&c);
return 0;
}
I just want to know, where and how the .sw file is reading in the above audio encoding code?
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'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 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;