#ifdef HAVE_LIBAV
+// determine whether we use libavformat from ffmpeg or from libav
+#define FFMPEG_LIBAVFORMAT (LIBAVFORMAT_VERSION_MICRO > 99 )
+// max_analyze_duration2 was used from ffmpeg libavformat 55.43.100 through 57.2.100
+#define FFMPEG_LIBAVFORMAT_MAX_DUR2 FFMPEG_LIBAVFORMAT && defined( \
+ (LIBAVFORMAT_VERSION_MAJOR == 55 && LIBAVFORMAT_VERSION_MINOR >= 43) \
+ || (LIBAVFORMAT_VERSION_MAJOR == 56) \
+ || (LIBAVFORMAT_VERSION_MAJOR == 57 && LIBAVFORMAT_VERSION_MINOR < 2) \
+ )
+
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavresample/avresample.h>
// hack to create or re-create the context the first time _do or _do_multi is called
void aubio_source_avcodec_reset_resampler(aubio_source_avcodec_t * s, uint_t multi);
+void aubio_source_avcodec_readframe(aubio_source_avcodec_t *s, uint_t * read_samples);
-aubio_source_avcodec_t * new_aubio_source_avcodec(char_t * path, uint_t samplerate, uint_t hop_size) {
+aubio_source_avcodec_t * new_aubio_source_avcodec(const char_t * path, uint_t samplerate, uint_t hop_size) {
aubio_source_avcodec_t * s = AUBIO_NEW(aubio_source_avcodec_t);
int err;
if (path == NULL) {
- AUBIO_ERR("Aborted opening null path\n");
+ AUBIO_ERR("source_avcodec: Aborted opening null path\n");
goto beach;
}
if ((sint_t)samplerate < 0) {
- AUBIO_ERR("Can not open %s with samplerate %d\n", path, samplerate);
+ AUBIO_ERR("source_avcodec: Can not open %s with samplerate %d\n", path, samplerate);
goto beach;
}
if ((sint_t)hop_size <= 0) {
- AUBIO_ERR("Can not open %s with hop_size %d\n", path, hop_size);
+ AUBIO_ERR("source_avcodec: Can not open %s with hop_size %d\n", path, hop_size);
goto beach;
}
s->hop_size = hop_size;
s->channels = 1;
- s->path = path;
+
+ if (s->path) AUBIO_FREE(s->path);
+ s->path = AUBIO_ARRAY(char_t, strnlen(path, PATH_MAX) + 1);
+ strncpy(s->path, path, strnlen(path, PATH_MAX) + 1);
// register all formats and codecs
av_register_all();
if ( (err = avformat_open_input(&avFormatCtx, s->path, NULL, NULL) ) < 0 ) {
char errorstr[256];
av_strerror (err, errorstr, sizeof(errorstr));
- AUBIO_ERR("Failed opening %s (%s)\n", s->path, errorstr);
+ AUBIO_ERR("source_avcodec: Failed opening %s (%s)\n", s->path, errorstr);
goto beach;
}
// try to make sure max_analyze_duration is big enough for most songs
+#if FFMPEG_LIBAVFORMAT_MAX_DUR2
+ avFormatCtx->max_analyze_duration2 *= 100;
+#else
avFormatCtx->max_analyze_duration *= 100;
+#endif
// retrieve stream information
if ( (err = avformat_find_stream_info(avFormatCtx, NULL)) < 0 ) {
char errorstr[256];
av_strerror (err, errorstr, sizeof(errorstr));
- AUBIO_ERR("Could not find stream information " "for %s (%s)\n", s->path,
+ AUBIO_ERR("source_avcodec: Could not find stream information " "for %s (%s)\n", s->path,
errorstr);
goto beach;
}
if (selected_stream == -1) {
selected_stream = i;
} else {
- AUBIO_WRN("More than one audio stream in %s, "
+ AUBIO_WRN("source_avcodec: More than one audio stream in %s, "
"taking the first one\n", s->path);
}
}
}
if (selected_stream == -1) {
- AUBIO_ERR("No audio stream in %s\n", s->path);
+ AUBIO_ERR("source_avcodec: No audio stream in %s\n", s->path);
goto beach;
}
//AUBIO_DBG("Taking stream %d in file %s\n", selected_stream, s->path);
avCodecCtx = avFormatCtx->streams[selected_stream]->codec;
AVCodec *codec = avcodec_find_decoder(avCodecCtx->codec_id);
if (codec == NULL) {
- AUBIO_ERR("Could not find decoder for %s", s->path);
+ AUBIO_ERR("source_avcodec: Could not find decoder for %s", s->path);
goto beach;
}
if ( ( err = avcodec_open2(avCodecCtx, codec, NULL) ) < 0) {
char errorstr[256];
av_strerror (err, errorstr, sizeof(errorstr));
- AUBIO_ERR("Could not load codec for %s (%s)\n", s->path, errorstr);
+ AUBIO_ERR("source_avcodec: Could not load codec for %s (%s)\n", s->path, errorstr);
goto beach;
}
//AUBIO_DBG("input_channels: %d\n", s->input_channels);
if (samplerate == 0) {
- samplerate = s->input_samplerate;
- //AUBIO_DBG("sampling rate set to 0, automagically adjusting to %d\n", samplerate);
+ s->samplerate = s->input_samplerate;
+ } else {
+ s->samplerate = samplerate;
}
- s->samplerate = samplerate;
if (s->samplerate > s->input_samplerate) {
- AUBIO_WRN("upsampling %s from %d to %d\n", s->path,
+ AUBIO_WRN("source_avcodec: upsampling %s from %d to %d\n", s->path,
s->input_samplerate, s->samplerate);
}
AVFrame *avFrame = s->avFrame;
- avFrame = avcodec_alloc_frame();
+ avFrame = av_frame_alloc();
if (!avFrame) {
- AUBIO_ERR("Could not allocate frame for (%s)\n", s->path);
+ AUBIO_ERR("source_avcodec: Could not allocate frame for (%s)\n", s->path);
}
/* allocate output for avr */
if ( ( err = avresample_open(avr) ) < 0) {
char errorstr[256];
av_strerror (err, errorstr, sizeof(errorstr));
- AUBIO_ERR("Could not open AVAudioResampleContext for %s (%s)\n",
+ AUBIO_ERR("source_avcodec: Could not open AVAudioResampleContext for %s (%s)\n",
s->path, errorstr);
//goto beach;
return;
(uint8_t **)&output, out_linesize, max_out_samples,
(uint8_t **)avFrame->data, in_linesize, in_samples);
if (out_samples <= 0) {
- AUBIO_ERR("No sample found while converting frame (%s)\n", s->path);
+ //AUBIO_ERR("No sample found while converting frame (%s)\n", s->path);
goto beach;
}
s->avr = avr;
s->output = output;
- av_free_packet(&avPacket);
+ av_packet_unref(&avPacket);
}
void aubio_source_avcodec_do(aubio_source_avcodec_t * s, fvec_t * read_data, uint_t * read){
*read = total_wrote;
}
-uint_t aubio_source_avcodec_get_samplerate(aubio_source_avcodec_t * s) {
+uint_t aubio_source_avcodec_get_samplerate(const aubio_source_avcodec_t * s) {
return s->samplerate;
}
-uint_t aubio_source_avcodec_get_channels(aubio_source_avcodec_t * s) {
+uint_t aubio_source_avcodec_get_channels(const aubio_source_avcodec_t * s) {
return s->input_channels;
}
uint_t aubio_source_avcodec_seek (aubio_source_avcodec_t * s, uint_t pos) {
- //uint_t resampled_pos = (uint_t)ROUND(pos * s->input_samplerate * 1. / s->samplerate);
- AUBIO_ERR("Not implemented, _seek(%d) file %s", pos, s->path);
- return -1; //sf_seek (s->handle, resampled_pos, SEEK_SET);
+ int64_t resampled_pos = (uint_t)ROUND(pos * (s->input_samplerate * 1. / s->samplerate));
+ int64_t min_ts = MAX(resampled_pos - 2000, 0);
+ int64_t max_ts = MIN(resampled_pos + 2000, INT64_MAX);
+ int seek_flags = AVSEEK_FLAG_FRAME | AVSEEK_FLAG_ANY;
+ int ret = avformat_seek_file(s->avFormatCtx, s->selected_stream,
+ min_ts, resampled_pos, max_ts, seek_flags);
+ if (ret < 0) {
+ AUBIO_ERR("Failed seeking to %d in file %s", pos, s->path);
+ }
+ // reset read status
+ s->eof = 0;
+ s->read_index = 0;
+ s->read_samples = 0;
+ // reset the AVAudioResampleContext
+ avresample_close(s->avr);
+ avresample_open(s->avr);
+ return ret;
}
-void del_aubio_source_avcodec(aubio_source_avcodec_t * s){
- if (!s) return;
- if (s->output != NULL) {
- av_free(s->output);
+uint_t aubio_source_avcodec_get_duration (aubio_source_avcodec_t * s) {
+ if (s && &(s->avFormatCtx) != NULL) {
+ int64_t duration = s->avFormatCtx->duration;
+ return s->samplerate * ((uint_t)duration / 1e6 );
}
+ return 0;
+}
+
+uint_t aubio_source_avcodec_close(aubio_source_avcodec_t * s) {
if (s->avr != NULL) {
avresample_close( s->avr );
av_free ( s->avr );
}
s->avr = NULL;
- if (s->avFrame != NULL) {
- avcodec_free_frame( &(s->avFrame) );
- }
- s->avFrame = NULL;
if (s->avCodecCtx != NULL) {
avcodec_close ( s->avCodecCtx );
}
if (s->avFormatCtx != NULL) {
avformat_close_input ( &(s->avFormatCtx) );
}
- s->avFrame = NULL;
s->avFormatCtx = NULL;
+ return AUBIO_OK;
+}
+
+void del_aubio_source_avcodec(aubio_source_avcodec_t * s){
+ if (!s) return;
+ aubio_source_avcodec_close(s);
+ if (s->output != NULL) {
+ av_free(s->output);
+ }
+ s->output = NULL;
+ if (s->avFrame != NULL) {
+ av_frame_free( &(s->avFrame) );
+ }
+ if (s->path) AUBIO_FREE(s->path);
+ s->avFrame = NULL;
AUBIO_FREE(s);
}