<NME> ffmpeg.c
<BEF> #include <stdlib.h>
#include <stdio.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavresample/avresample.h>
#include <libavutil/opt.h>
#include "ffmpeg.h"

struct ffmpeg_state {
	AVFormatContext *container;
	AVCodecContext *cc;
	AVAudioResampleContext *avr;
	AVFrame *frame;
	AVPacket packet;
	int bytes, stream_index;
};

static int av_registered = 0;

ssize_t ffmpeg_read(struct codec *c, sample_t *buf, ssize_t frames)
{
	struct ffmpeg_state *state = (struct ffmpeg_state *) c->data;
	sample_t *buf_ptr;
	int avail, len, got_frame = 0, done = 0;
	ssize_t buf_pos = 0, samples = frames * c->channels;
	avail = avresample_available(state->avr);
	while (buf_pos < samples && !(done && avail == 0)) {
		if (avail == 0) {
			skip_frame:
			if (state->packet.size <= 0) {
	if ((r = avcodec_receive_frame(state->cc, state->frame)) < 0) {
		switch (r) {
		case AVERROR_EOF:
			return -1;
				}
			}
			if (state->packet.stream_index == state->stream_index) {
				got_frame = 0;
				if ((len = avcodec_decode_audio4(state->cc, state->frame, &got_frame, &state->packet)) < 0) {
					state->packet.size = 0;
					goto skip_frame;
				}
				state->packet.size -= len;
				state->packet.data += len;
				if (!got_frame)
					goto skip_frame;

				avresample_convert(state->avr, NULL, 0, 0, state->frame->data, state->frame->linesize[0], state->frame->nb_samples);
				av_frame_unref(state->frame);
			}
			else
				state->packet.size = 0;
		}
		else {
			avail = (avail > (samples - buf_pos) / c->channels) ? (samples - buf_pos) / c->channels : avail;
			buf_ptr = &buf[buf_pos];
			avail = avresample_read(state->avr, (uint8_t **) &buf_ptr, avail);
			buf_pos += avail * c->channels;
		}
		avail = avresample_available(state->avr);
	}
	return buf_pos / c->channels;
}

ssize_t ffmpeg_write(struct codec *c, sample_t *buf, ssize_t frames)
				done = 1;
				continue;
			}
			else if (r > 0)
				return 0;
		}
		if (state->got_frame) {
			avail = (avail > frames - buf_pos) ? frames - buf_pos : avail;
			if (state->planar)
				state->readp_func((char **) state->frame->extended_data, &buf[buf_pos * c->channels],
					c->channels, state->frame_pos, avail);
			else
				state->read_func((char *) &state->frame->extended_data[0][state->frame_pos * state->bytes * c->channels],
					&buf[buf_pos * c->channels], avail * c->channels);
			buf_pos += avail;
	timestamp = pos * time_base.den / time_base.num / c->fs;
	if (av_seek_frame(state->container, state->stream_index, timestamp, AVSEEK_FLAG_FRAME) < 0)
		return -1;
	/* drop any pending frames in the output FIFO */
	avresample_close(state->avr);
	avresample_open(state->avr);
	return pos;
}

{
	return 0;
}

ssize_t ffmpeg_seek(struct codec *c, ssize_t pos)
{
	AVStream *st;
	int64_t seek_ts;
	struct ffmpeg_state *state = (struct ffmpeg_state *) c->data;
	if (c->frames == -1)
		return -1;
	if (pos < 0)
		pos = 0;
	else if (pos >= c->frames)
		pos = c->frames - 1;
	st = state->container->streams[state->stream_index];
	seek_ts = av_rescale(pos, st->time_base.den, st->time_base.num) / c->fs;
	struct ffmpeg_state *state = (struct ffmpeg_state *) c->data;
	av_free_packet(&state->packet);
	av_frame_free(&state->frame);
	avresample_free(&state->avr);
	avformat_close_input(&state->container);
	free(state);
	free((char *) c->type);
}

ssize_t ffmpeg_delay(struct codec *c)
{
	return 0;
}

void ffmpeg_drop(struct codec *c)
{
	/* do nothing */
}

void ffmpeg_pause(struct codec *c, int p)
{
	/* do nothing */
}

void ffmpeg_destroy(struct codec *c)
{
	struct ffmpeg_state *state = (struct ffmpeg_state *) c->data;
	av_frame_free(&state->frame);
	avcodec_free_context(&state->cc);
	avformat_close_input(&state->container);
	free(state);
	free((char *) c->type);
}

struct codec * ffmpeg_codec_init(const char *path, const char *type, const char *enc, int fs, int channels, int endian, int mode)
{
	int i, err;
	struct ffmpeg_state *state = NULL;
	struct codec *c = NULL;
	AVStream *st;
	const AVCodec *codec = NULL;

	if (!av_initialized) {
		if (LOGLEVEL(LL_VERBOSE))
			av_log_set_level(AV_LOG_VERBOSE);
		else if (LOGLEVEL(LL_SILENT))
			av_log_set_level(AV_LOG_QUIET);
		av_initialized = 1;
	}

	/* open input and find stream info */
	state = calloc(1, sizeof(struct ffmpeg_state));
	if ((err = avformat_open_input(&state->container, path, NULL, NULL)) < 0) {
		LOG(LL_ERROR, "dsp: ffmpeg: error: failed to allocate frame\n");
		goto fail;
	}

	/* set up avresample */
	state->avr = avresample_alloc_context();
	av_opt_set_int(state->avr, "in_channel_layout", state->cc->channel_layout, 0);
	av_opt_set_int(state->avr, "out_channel_layout", state->cc->channel_layout, 0);
	av_opt_set_int(state->avr, "in_sample_rate", state->cc->sample_rate, 0);
	av_opt_set_int(state->avr, "out_sample_rate", state->cc->sample_rate, 0);
	av_opt_set_int(state->avr, "in_sample_fmt", state->cc->sample_fmt, 0);
	av_opt_set_int(state->avr, "out_sample_fmt", AV_SAMPLE_FMT_DBL, 0);
	if ((err = avresample_open(state->avr)) < 0) {
		LOG(LL_ERROR, "dsp: ffmpeg: error: could not open audio resample context: %s\n", av_err2str(err));
		goto fail;
	}
	state->bytes = av_get_bytes_per_sample(state->cc->sample_fmt);

	c = calloc(1, sizeof(struct codec));
	}

	/* find audio stream */
	state->stream_index = av_find_best_stream(state->container, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
	if (state->stream_index < 0) {
		LOG_FMT(LL_ERROR, "%s: error: could not find an audio stream", codec_name);
		goto fail;
	case AV_SAMPLE_FMT_U8:
	case AV_SAMPLE_FMT_U8P:
		c->prec = 8;
		break;
	case AV_SAMPLE_FMT_S16:
	case AV_SAMPLE_FMT_S16P:
		c->prec = 16;
		break;
	case AV_SAMPLE_FMT_S32:
	case AV_SAMPLE_FMT_S32P:
		c->prec = 32;
		break;
	case AV_SAMPLE_FMT_FLT:
	case AV_SAMPLE_FMT_FLTP:
		c->prec = 24;
		break;
	case AV_SAMPLE_FMT_DBL:
	case AV_SAMPLE_FMT_DBLP:
		c->prec = 53;
		break;
	default:
		c->prec = 16;
	}
	c->channels = state->cc->channels;
	time_base.num = state->container->streams[state->stream_index]->time_base.num;
	c->enc = av_get_sample_fmt_name(state->cc->sample_fmt);
	c->fs = state->cc->sample_rate;
	#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59, 37, 100)
		c->channels = state->cc->ch_layout.nb_channels;
	#else
		c->channels = state->cc->channels;
	#endif
	switch (state->cc->sample_fmt) {
	case AV_SAMPLE_FMT_U8:
	case AV_SAMPLE_FMT_U8P:
		c->prec = 8;
	return c;

	fail:
	if (state->avr != NULL)
		avresample_free(&state->avr);
	if (state->frame != NULL)
		av_frame_free(&state->frame);
	if (state->container != NULL)
		c->prec = 16;
		c->can_dither = 1;
		state->read_func = read_buf_s16;
		state->readp_func = read_buf_s16p;
		break;
	case AV_SAMPLE_FMT_S32:
	case AV_SAMPLE_FMT_S32P:
		c->prec = 32;
		c->can_dither = 1;
		state->read_func = read_buf_s32;
		state->readp_func = read_buf_s32p;
		break;
	case AV_SAMPLE_FMT_FLT:
	case AV_SAMPLE_FMT_FLTP:
		c->prec = 24;
		state->read_func = read_buf_float;
		state->readp_func = read_buf_floatp;
		break;
	case AV_SAMPLE_FMT_DBL:
	case AV_SAMPLE_FMT_DBLP:
		c->prec = 53;
		state->read_func = read_buf_double;
		state->readp_func = read_buf_doublep;
		break;
	default:
		LOG_FMT(LL_ERROR, "%s: error: unhandled sample format", codec_name);
		goto fail;
	}
	if (st->duration != AV_NOPTS_VALUE)
		c->frames = av_rescale(st->duration, st->time_base.num * c->fs, st->time_base.den);
	else if (state->container->duration != AV_NOPTS_VALUE)
		c->frames = av_rescale(state->container->duration, c->fs, AV_TIME_BASE);
	else
		c->frames = -1;
	c->read = ffmpeg_read;
	c->write = ffmpeg_write;
	c->seek = ffmpeg_seek;
	c->delay = ffmpeg_delay;
	c->drop = ffmpeg_drop;
	c->pause = ffmpeg_pause;
	c->destroy = ffmpeg_destroy;
	c->data = state;

	return c;

	fail:
	free(c);
	if (state->frame)
		av_frame_free(&state->frame);
	if (state->cc)
		avcodec_close(state->cc);
	if (state->container)
		avformat_close_input(&state->container);
	free(state);
	return NULL;
}

void ffmpeg_codec_print_encodings(const char *type)
{
	fprintf(stdout, " <autodetected>");
}

<MSG> ffmpeg.c: Drop libavresample dependency.

<DFF> @@ -2,29 +2,93 @@
 #include <stdio.h>
 #include <libavcodec/avcodec.h>
 #include <libavformat/avformat.h>
-#include <libavresample/avresample.h>
 #include <libavutil/opt.h>
 #include "ffmpeg.h"
+#include "sampleconv.h"
 
 struct ffmpeg_state {
 	AVFormatContext *container;
 	AVCodecContext *cc;
-	AVAudioResampleContext *avr;
 	AVFrame *frame;
 	AVPacket packet;
-	int bytes, stream_index;
+	void (*read_func)(char *, sample_t *, ssize_t);
+	void (*readp_func)(char **, sample_t *, int, ssize_t, ssize_t);
+	int planar, bytes, stream_index, got_frame;
+	ssize_t frame_pos;
 };
 
 static int av_registered = 0;
 
+/* Planar sample conversion functions */
+
+static void read_buf_u8p(char **in, sample_t *out, int channels, ssize_t start, ssize_t s)
+{
+	unsigned char **inn = (unsigned char **) in;
+	int c = channels;
+	ssize_t out_s = s * channels;
+	while (s-- > 0) {
+		while (c-- > 0)
+			out[--out_s] = U8_TO_SAMPLE(inn[c][start + s]);
+		c = channels;
+	}
+}
+
+static void read_buf_s16p(char **in, sample_t *out, int channels, ssize_t start, ssize_t s)
+{
+	signed short **inn = (signed short **) in;
+	int c = channels;
+	ssize_t out_s = s * channels;
+	while (s-- > 0) {
+		while (c-- > 0)
+			out[--out_s] = S16_TO_SAMPLE(inn[c][start + s]);
+		c = channels;
+	}
+}
+
+static void read_buf_s32p(char **in, sample_t *out, int channels, ssize_t start, ssize_t s)
+{
+	signed int **inn = (signed int **) in;
+	int c = channels;
+	ssize_t out_s = s * channels;
+	while (s-- > 0) {
+		while (c-- > 0)
+			out[--out_s] = S32_TO_SAMPLE(inn[c][start + s]);
+		c = channels;
+	}
+}
+
+static void read_buf_floatp(char **in, sample_t *out, int channels, ssize_t start, ssize_t s)
+{
+	float **inn = (float **) in;
+	int c = channels;
+	ssize_t out_s = s * channels;
+	while (s-- > 0) {
+		while (c-- > 0)
+			out[--out_s] = FLOAT_TO_SAMPLE(inn[c][start + s]);
+		c = channels;
+	}
+}
+
+static void read_buf_doublep(char **in, sample_t *out, int channels, ssize_t start, ssize_t s)
+{
+	double **inn = (double **) in;
+	int c = channels;
+	ssize_t out_s = s * channels;
+	while (s-- > 0) {
+		while (c-- > 0)
+			out[--out_s] = DOUBLE_TO_SAMPLE(inn[c][start + s]);
+		c = channels;
+	}
+}
+
 ssize_t ffmpeg_read(struct codec *c, sample_t *buf, ssize_t frames)
 {
 	struct ffmpeg_state *state = (struct ffmpeg_state *) c->data;
-	sample_t *buf_ptr;
-	int avail, len, got_frame = 0, done = 0;
-	ssize_t buf_pos = 0, samples = frames * c->channels;
-	avail = avresample_available(state->avr);
-	while (buf_pos < samples && !(done && avail == 0)) {
+	int len, done = 0;
+	ssize_t buf_pos = 0, avail = 0;
+	if (state->got_frame)
+		avail = state->frame->nb_samples - state->frame_pos;
+	while (buf_pos < frames && !(done && avail == 0)) {
 		if (avail == 0) {
 			skip_frame:
 			if (state->packet.size <= 0) {
@@ -35,31 +99,34 @@ ssize_t ffmpeg_read(struct codec *c, sample_t *buf, ssize_t frames)
 				}
 			}
 			if (state->packet.stream_index == state->stream_index) {
-				got_frame = 0;
-				if ((len = avcodec_decode_audio4(state->cc, state->frame, &got_frame, &state->packet)) < 0) {
+				state->got_frame = 0;
+				state->frame_pos = 0;
+				av_frame_unref(state->frame);
+				if ((len = avcodec_decode_audio4(state->cc, state->frame, &state->got_frame, &state->packet)) < 0) {
 					state->packet.size = 0;
 					goto skip_frame;
 				}
 				state->packet.size -= len;
 				state->packet.data += len;
-				if (!got_frame)
+				if (!state->got_frame)
 					goto skip_frame;
-
-				avresample_convert(state->avr, NULL, 0, 0, state->frame->data, state->frame->linesize[0], state->frame->nb_samples);
-				av_frame_unref(state->frame);
 			}
 			else
 				state->packet.size = 0;
 		}
-		else {
-			avail = (avail > (samples - buf_pos) / c->channels) ? (samples - buf_pos) / c->channels : avail;
-			buf_ptr = &buf[buf_pos];
-			avail = avresample_read(state->avr, (uint8_t **) &buf_ptr, avail);
-			buf_pos += avail * c->channels;
+		else if (state->got_frame) {
+			avail = (avail > frames - buf_pos) ? frames - buf_pos : avail;
+			if (state->planar)
+				state->readp_func((char **) state->frame->extended_data, &buf[buf_pos * c->channels], c->channels, state->frame_pos, avail);
+			else
+				state->read_func((char *) &state->frame->extended_data[0][state->frame_pos * state->bytes * c->channels], &buf[buf_pos * c->channels], avail * c->channels);
+			buf_pos += avail;
+			state->frame_pos += avail;
 		}
-		avail = avresample_available(state->avr);
+		if (state->got_frame)
+			avail = state->frame->nb_samples - state->frame_pos;
 	}
-	return buf_pos / c->channels;
+	return buf_pos;
 }
 
 ssize_t ffmpeg_write(struct codec *c, sample_t *buf, ssize_t frames)
@@ -81,9 +148,8 @@ ssize_t ffmpeg_seek(struct codec *c, ssize_t pos)
 	timestamp = pos * time_base.den / time_base.num / c->fs;
 	if (av_seek_frame(state->container, state->stream_index, timestamp, AVSEEK_FLAG_FRAME) < 0)
 		return -1;
-	/* drop any pending frames in the output FIFO */
-	avresample_close(state->avr);
-	avresample_open(state->avr);
+	state->got_frame = 0;
+	state->packet.size = 0;
 	return pos;
 }
 
@@ -107,7 +173,6 @@ void ffmpeg_destroy(struct codec *c)
 	struct ffmpeg_state *state = (struct ffmpeg_state *) c->data;
 	av_free_packet(&state->packet);
 	av_frame_free(&state->frame);
-	avresample_free(&state->avr);
 	avformat_close_input(&state->container);
 	free(state);
 	free((char *) c->type);
@@ -160,19 +225,7 @@ struct codec * ffmpeg_codec_init(const char *type, int mode, const char *path, c
 		LOG(LL_ERROR, "dsp: ffmpeg: error: failed to allocate frame\n");
 		goto fail;
 	}
-
-	/* set up avresample */
-	state->avr = avresample_alloc_context();
-	av_opt_set_int(state->avr, "in_channel_layout", state->cc->channel_layout, 0);
-	av_opt_set_int(state->avr, "out_channel_layout", state->cc->channel_layout, 0);
-	av_opt_set_int(state->avr, "in_sample_rate", state->cc->sample_rate, 0);
-	av_opt_set_int(state->avr, "out_sample_rate", state->cc->sample_rate, 0);
-	av_opt_set_int(state->avr, "in_sample_fmt", state->cc->sample_fmt, 0);
-	av_opt_set_int(state->avr, "out_sample_fmt", AV_SAMPLE_FMT_DBL, 0);
-	if ((err = avresample_open(state->avr)) < 0) {
-		LOG(LL_ERROR, "dsp: ffmpeg: error: could not open audio resample context: %s\n", av_err2str(err));
-		goto fail;
-	}
+	state->planar = av_sample_fmt_is_planar(state->cc->sample_fmt);
 	state->bytes = av_get_bytes_per_sample(state->cc->sample_fmt);
 
 	c = calloc(1, sizeof(struct codec));
@@ -186,25 +239,36 @@ struct codec * ffmpeg_codec_init(const char *type, int mode, const char *path, c
 	case AV_SAMPLE_FMT_U8:
 	case AV_SAMPLE_FMT_U8P:
 		c->prec = 8;
+		state->read_func = read_buf_u8;
+		state->readp_func = read_buf_u8p;
 		break;
 	case AV_SAMPLE_FMT_S16:
 	case AV_SAMPLE_FMT_S16P:
 		c->prec = 16;
+		state->read_func = read_buf_s16;
+		state->readp_func = read_buf_s16p;
 		break;
 	case AV_SAMPLE_FMT_S32:
 	case AV_SAMPLE_FMT_S32P:
 		c->prec = 32;
+		state->read_func = read_buf_s32;
+		state->readp_func = read_buf_s32p;
 		break;
 	case AV_SAMPLE_FMT_FLT:
 	case AV_SAMPLE_FMT_FLTP:
 		c->prec = 24;
+		state->read_func = read_buf_float;
+		state->readp_func = read_buf_floatp;
 		break;
 	case AV_SAMPLE_FMT_DBL:
 	case AV_SAMPLE_FMT_DBLP:
 		c->prec = 53;
+		state->read_func = read_buf_double;
+		state->readp_func = read_buf_doublep;
 		break;
 	default:
-		c->prec = 16;
+		LOG(LL_ERROR, "dsp: ffmpeg: error: unhandled sample format\n");
+		goto fail;
 	}
 	c->channels = state->cc->channels;
 	time_base.num = state->container->streams[state->stream_index]->time_base.num;
@@ -222,8 +286,6 @@ struct codec * ffmpeg_codec_init(const char *type, int mode, const char *path, c
 	return c;
 
 	fail:
-	if (state->avr != NULL)
-		avresample_free(&state->avr);
 	if (state->frame != NULL)
 		av_frame_free(&state->frame);
 	if (state->container != NULL)

{'addition_count': 103, 'commit_subject': 'ffmpeg.c: Drop libavresample dependency.', 'deletion_count': 41, 'file_extension': '.c', 'lang': 'c', 'license': 'isc', 'repo_name': 'bmc0/dsp'}