Skip to content

Instantly share code, notes, and snippets.

@noobed
Created November 7, 2013 11:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save noobed/7353451 to your computer and use it in GitHub Desktop.
Save noobed/7353451 to your computer and use it in GitHub Desktop.
convert.cpp is used to get raw audio date and save it in file : "myOutputTest"
#ifdef __cplusplus
#define __STDC_CONSTANT_MACROS
#ifdef _STDINT_H
#undef _STDINT_H
#endif
#endif
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavutil/samplefmt.h>
#include <libavutil/frame.h>
#include <libavutil/timestamp.h>
#include <libavutil/opt.h>
#include <libswresample/swresample.h>
}
#include <stdio.h>
#include <stdint.h>
AVStream * audio_stream;
AVCodecContext * audio_dec_ctx;
AVFrame *frame = NULL;
AVPacket pkt;
AVFormatContext *avFormatContext = NULL;
AVCodec *pCodec = NULL;
AVCodecContext * pCodecContext;
int audioStreamId = -1;
FILE * audio_dst_filename;
int audio_frame_count = 0;
//libswresample:
SwrContext *swr_ctx;
//int64_t src_ch_layout = AV_CH_LAYOUT_STEREO;
int64_t dst_ch_layout = AV_CH_LAYOUT_STEREO; //I don't need surround at the moment! AV_CH_LAYOUT_SURROUND;
int src_rate = 44100;
int dst_rate = 44100;
//uint8_t **src_data = NULL;
uint8_t **dst_data = NULL;
int src_nb_channels = 0, dst_nb_channels = 0;
int src_linesize, dst_linesize;
int src_nb_samples = 1024, dst_nb_samples, max_dst_nb_samples;
// enum AVSampleFormat src_sample_fmt = AV_SAMPLE_FMT_DBL;
enum AVSampleFormat dst_sample_fmt = AV_SAMPLE_FMT_S16; //this represents the type of data it's hold by the buffer - whether it's an float or int...
const char *dst_filename = NULL;
FILE *dst_file;
int dst_bufsize;
const char *fmt;
//declaring some functions
int check_sample_fmt(AVCodec *codec, enum AVSampleFormat sample_fmt);
int select_sample_rate(AVCodec *codec);
int select_channel_layout(AVCodec *codec);
void audio_encode_example(const char *filename);
//originally taken from: http://ffmpeg.org/doxygen/trunk/doc_2examples_2demuxing_decoding_8c-example.html
int decode_packet(int *got_frame, int cached)
{
int ret = 0;
int decoded = pkt.size;
if (pkt.stream_index == audioStreamId)
{
/* decode audio frame */
ret = avcodec_decode_audio4(audio_dec_ctx, frame, got_frame, &pkt);
if (ret < 0) {
fprintf(stderr, "Error decoding audio frame\n");
return ret;
}
/* Some audio decoders decode only part of the packet, and have to be
* called again with the remainder of the packet data.
* Sample: fate-suite/lossless-audio/luckynight-partial.shn
* Also, some decoders might over-read the packet. */
decoded = FFMIN(ret, pkt.size);
if (*got_frame) {
/* Write the raw audio data samples of the first plane. This works
* fine for packed formats (e.g. AV_SAMPLE_FMT_S16). However,
* most audio decoders output planar audio, which uses a separate
* plane of audio samples for each channel (e.g. AV_SAMPLE_FMT_S16P).
* In other words, this code will write only the first audio channel
* in these cases.
* You should use libswresample or libavfilter to convert the frame
* to packed data.
*/
/* compute destination number of samples */
dst_nb_samples = av_rescale_rnd(swr_get_delay(swr_ctx, src_rate) +
frame->nb_samples,/* src_nb_samples,*/ dst_rate, src_rate, AV_ROUND_UP);
if (dst_nb_samples > max_dst_nb_samples)
{
av_free(dst_data[0]);
ret = av_samples_alloc(dst_data, &dst_linesize, dst_nb_channels,
dst_nb_samples, dst_sample_fmt, 1);
if (ret < 0)
{
fprintf(stderr, "Error while av_sample_alloc\n");
return -112;
}
max_dst_nb_samples = dst_nb_samples;
}
//modified using this example: http://ffmpeg.org/doxygen/trunk/doc_2examples_2resampling_audio_8c-example.html
/* convert to destination format */
ret = swr_convert(swr_ctx, dst_data, dst_nb_samples, (const uint8_t **)frame->extended_data,frame->nb_samples);
if (ret < 0)
{
fprintf(stderr, "Error while converting\n");
return -111;
}
dst_bufsize = av_samples_get_buffer_size(&dst_linesize, dst_nb_channels,
ret, dst_sample_fmt, 1);
printf("in:%d out:%d\n", src_nb_samples, ret);
fwrite(dst_data[0], 1, dst_bufsize, audio_dst_filename);//dst_file);
}
}
return decoded;
}
int get_format_from_sample_fmt(const char **fmt,
enum AVSampleFormat sample_fmt)
{
int i;
struct sample_fmt_entry {
enum AVSampleFormat sample_fmt;
const char *fmt_be, *fmt_le;
} sample_fmt_entries[] = {
{ AV_SAMPLE_FMT_U8, "u8", "u8" },
{ AV_SAMPLE_FMT_S16, "s16be", "s16le" },
{ AV_SAMPLE_FMT_S32, "s32be", "s32le" },
{ AV_SAMPLE_FMT_FLT, "f32be", "f32le" },
{ AV_SAMPLE_FMT_DBL, "f64be", "f64le" },
};
*fmt = NULL;
for (i = 0; i < FF_ARRAY_ELEMS(sample_fmt_entries); i++) {
struct sample_fmt_entry *entry = &sample_fmt_entries[i];
if (sample_fmt == entry->sample_fmt) {
*fmt = AV_NE(entry->fmt_be, entry->fmt_le);
return 0;
}
}
fprintf(stderr,
"sample format %s is not supported as output format\n",
av_get_sample_fmt_name(sample_fmt));
return -1;
}
typedef struct SampleFmtInfo {
char name[8];
int bits;
int planar;
enum AVSampleFormat altform; ///< planar<->packed alternative form
} SampleFmtInfo;
const SampleFmtInfo sample_fmt_info[AV_SAMPLE_FMT_NB] = {
{ "u8", 8, 0, AV_SAMPLE_FMT_U8P },
{ "s16", 16, 0, AV_SAMPLE_FMT_S16P },
{ "s32", 32, 0, AV_SAMPLE_FMT_S32P },
{ "flt", 32, 0, AV_SAMPLE_FMT_FLTP },
{ "dbl", 64, 0, AV_SAMPLE_FMT_DBLP },
{ "u8p", 8, 1, AV_SAMPLE_FMT_U8 },
{ "s16p", 16, 1, AV_SAMPLE_FMT_S16 },
{ "s32p", 32, 1, AV_SAMPLE_FMT_S32 },
{ "fltp", 32, 1, AV_SAMPLE_FMT_FLT },
{ "dblp", 64, 1, AV_SAMPLE_FMT_DBL },
};
static const struct
{
const char *name;
int nb_channels;
uint64_t layout;
} channel_layout_map[] =
{
{ "mono", 1, AV_CH_LAYOUT_MONO },
{ "stereo", 2, AV_CH_LAYOUT_STEREO },
{ "2.1", 3, AV_CH_LAYOUT_2POINT1 },
{ "3.0", 3, AV_CH_LAYOUT_SURROUND },
{ "3.0(back)", 3, AV_CH_LAYOUT_2_1 },
{ "4.0", 4, AV_CH_LAYOUT_4POINT0 },
{ "quad", 4, AV_CH_LAYOUT_QUAD },
{ "quad(side)", 4, AV_CH_LAYOUT_2_2 },
{ "3.1", 4, AV_CH_LAYOUT_3POINT1 },
{ "5.0", 5, AV_CH_LAYOUT_5POINT0_BACK },
{ "5.0(side)", 5, AV_CH_LAYOUT_5POINT0 },
{ "4.1", 5, AV_CH_LAYOUT_4POINT1 },
{ "5.1", 6, AV_CH_LAYOUT_5POINT1_BACK },
{ "5.1(side)", 6, AV_CH_LAYOUT_5POINT1 },
{ "6.0", 6, AV_CH_LAYOUT_6POINT0 },
{ "6.0(front)", 6, AV_CH_LAYOUT_6POINT0_FRONT },
{ "hexagonal", 6, AV_CH_LAYOUT_HEXAGONAL },
{ "6.1", 7, AV_CH_LAYOUT_6POINT1 },
{ "6.1", 7, AV_CH_LAYOUT_6POINT1_BACK },
{ "6.1(front)", 7, AV_CH_LAYOUT_6POINT1_FRONT },
{ "7.0", 7, AV_CH_LAYOUT_7POINT0 },
{ "7.0(front)", 7, AV_CH_LAYOUT_7POINT0_FRONT },
{ "7.1", 8, AV_CH_LAYOUT_7POINT1 },
{ "7.1(wide-side)", 8, AV_CH_LAYOUT_7POINT1_WIDE },
{ "octagonal", 8, AV_CH_LAYOUT_OCTAGONAL },
{ "downmix", 2, AV_CH_LAYOUT_STEREO_DOWNMIX, },
};
int main(int argc, char * argv[])
{
if(argc < 2)
{
printf("you need to specify filename \n");
return -1;
}
//This registers all available file formats and codecs with the library so they will be used automatically when a file with the corresponding format/codec is opened. Note that you only need to call av_register_all() once, so we do it here in main(). If you like, it's possible to register only certain individual file formats and codecs, but there's usually no reason why you would have to do that.
avcodec_register_all();
av_register_all();
//opening audio/video file
int ret = avformat_open_input(&avFormatContext, argv[1], NULL, NULL);
if (ret < 0)
return -2; // Couldn't open file
for(int i = 0; i < avFormatContext->nb_streams; i++)
{
if(avFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)//CODEC_TYPE_AUDIO)
{
audioStreamId = i;
break;
}
}
if(audioStreamId == -1)
return -3; //Didn't find an audio stream
pCodecContext = avFormatContext->streams[audioStreamId]->codec;
if(pCodecContext == NULL)
return -10;
//The stream's information about the codec is in what we call the "codec context." This contains all the information about the codec that the stream is using, and now we have a pointer to it. But we still have to find the actual codec and open it:
//Find the decoder for the audio stream
pCodec = avcodec_find_decoder(pCodecContext->codec_id);
if(pCodec == NULL)
return -4; //Codec not found
//Open codec
//avcodec_open2 - This function is not thread safe!
//Prior to using this function the context has to be allocated with avcodec_alloc_context3().
//pCodecContext = avcodec_alloc_context3(pCodec); this has to be commented in order to process flv files!
//Extradata missing error ?!
if(pCodecContext == NULL)
return -5; //Could not allocate audio codec context
if(avcodec_open2(pCodecContext, pCodec, NULL) < 0)
return -6; //Couldn't open codec
audio_stream = avFormatContext->streams[audioStreamId];
audio_dec_ctx = audio_stream->codec;
audio_dst_filename = fopen("myOutputTest", "wb");
if(!audio_dst_filename)
return -7; //Couldn't open output file
frame = avcodec_alloc_frame();
if (!frame)
return -8;//fprintf(stderr, "Could not allocate frame\n");
//libswresample initialization: originally main() -> http://ffmpeg.org/doxygen/trunk/doc_2examples_2resampling_audio_8c-example.html
/* initialize the resampling context */
/* create resampler context */
swr_ctx = swr_alloc();
if (!swr_ctx)
{
fprintf(stderr, "Could not allocate resampler context\n");
return -100;
}
/* set options */
av_opt_set_int(swr_ctx, "in_channel_layout", pCodecContext->channel_layout, 0); //src_ch_layout, 0);
av_opt_set_int(swr_ctx, "in_sample_rate", pCodecContext->sample_rate, 0); //src_rate, 0);
av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", pCodecContext->sample_fmt, 0); //src_sample_fmt, 0);
av_opt_set_int(swr_ctx, "out_channel_layout", dst_ch_layout, 0); //STEREO
av_opt_set_int(swr_ctx, "out_sample_rate", dst_rate, 0); //44100
av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", dst_sample_fmt, 0); //S16
//exception
src_rate = pCodecContext->sample_rate;
//end of exception
/* initialize the resampling context */
if ((ret = swr_init(swr_ctx)) < 0) {
fprintf(stderr, "Failed to initialize the resampling context\n");
return -101;
}
/* allocate source and destination samples buffers */
/* compute the number of converted samples: buffering is avoided
* ensuring that the output buffer will contain at least all the
* converted input samples */
max_dst_nb_samples = dst_nb_samples = av_rescale_rnd(src_nb_samples, dst_rate, pCodecContext->sample_rate, //src_rate,
AV_ROUND_UP);
/* buffer is going to be directly written to a rawaudio file, no alignment */
dst_nb_channels = av_get_channel_layout_nb_channels(dst_ch_layout);
ret = av_samples_alloc_array_and_samples(&dst_data, &dst_linesize, dst_nb_channels,
dst_nb_samples, dst_sample_fmt, 0);
if (ret < 0) {
fprintf(stderr, "Could not allocate destination samples\n");
return -102;
}
/* initialize packet, set data to NULL, let the demuxer fill it */
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
int got_frame;
/* read frames from the file */
while (av_read_frame(avFormatContext, &pkt) >= 0)
{
AVPacket orig_pkt = pkt;
do
{
ret = decode_packet(&got_frame, 0);
if (ret < 0)
break;
pkt.data += ret;
pkt.size -= ret;
} while (pkt.size > 0);
av_free_packet(&orig_pkt);
}
/* flush cached frames */
pkt.data = NULL;
pkt.size = 0;
//such a do while tends to be infinite
//do {
decode_packet(&got_frame, 1);
//} while (got_frame);
if (audio_stream) {
printf("Play the output audio file with the command:\n"
"ffplay -f %s -ac %d -ar %d\n",
"s16le", 2, 44100);
}
if (pCodecContext)
avcodec_close(pCodecContext);
if (audio_dst_filename)
fclose(audio_dst_filename);
av_free(frame);
avformat_close_input(&avFormatContext);
return 0;
}
int check_sample_fmt(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;
}
int select_sample_rate(AVCodec *codec)
{
const int *p;
int best_samplerate = 0;
if (!codec->supported_samplerates)
return 44100;
p = codec->supported_samplerates;
while (*p) {
best_samplerate = FFMAX(*p, best_samplerate);
p++;
}
return best_samplerate;
}
/* select layout with the highest channel count */
int select_channel_layout(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;
}
all:
g++ -o convert.o convert.cpp \
-L/usr/local/lib -I/usr/local/include \
-lavformat -lavcodec -lavutil -lswresample -lfaac -lmp3lame -lvpx -lx264 -lavdevice -lswscale -lrtmp -lvorbis \
-lvorbisenc -ltheora -lva -lz \
-pthread
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment