[gegl/video-rejuvenation: 57/60] ff-save: audio data is now stereo float
- From: Øyvind Kolås <ok src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl/video-rejuvenation: 57/60] ff-save: audio data is now stereo float
- Date: Mon, 16 Nov 2015 22:18:16 +0000 (UTC)
commit ad02c6070cd1757f0a2683d966dd35cb727c914d
Author: Øyvind Kolås <pippin gimp org>
Date: Sat Nov 14 22:25:32 2015 +0100
ff-save: audio data is now stereo float
operations/external/ff-save.c | 399 ++++++++++++++++++++---------------------
1 files changed, 195 insertions(+), 204 deletions(-)
---
diff --git a/operations/external/ff-save.c b/operations/external/ff-save.c
index dbb2e0a..730d8f1 100644
--- a/operations/external/ff-save.c
+++ b/operations/external/ff-save.c
@@ -27,7 +27,7 @@
property_string (path, _("File"), "/tmp/fnord.ogv")
description (_("Target path and filename, use '-' for stdout."))
property_string (video_codec, _("Audio codec"), "auto")
-property_double (video_bit_rate, _("video bitrate"), 810000.0)
+property_int (video_bit_rate, _("video bitrate"), 810000)
value_range (0.0, 500000000.0)
#if 0
property_double (video_bit_rate_tolerance, _("video bitrate"), 1000.0)
@@ -42,7 +42,8 @@ property_double (frame_rate, _("Frames/second"), 25.0)
value_range (0.0, 100.0)
property_string (audio_codec, _("Audio codec"), "auto")
-property_double (audio_bit_rate, _("video bitrate"), 810000.0)
+property_int (audio_sample_rate, _("Audio sample rate"), 48000)
+property_int (audio_bit_rate, _("Audio bitrate"), 810000)
property_audio (audio, _("audio"), 0)
@@ -63,6 +64,18 @@ property_audio (audio, _("audio"), 0)
#include <libavutil/opt.h>
#include <libswscale/swscale.h>
+#define MAX_AUDIO_CHANNELS 6
+#define MAX_AUDIO_SAMPLES 2048
+
+typedef struct AudioFrame {
+ //int64_t pts;
+ float data[MAX_AUDIO_CHANNELS][MAX_AUDIO_SAMPLES];
+ int channels;
+ int sample_rate;
+ int len;
+ long pos;
+} AudioFrame;
+
typedef struct
{
gdouble frame;
@@ -120,12 +133,73 @@ typedef struct
int audio_input_frame_size;
int16_t *samples;
uint8_t *audio_outbuf;
+
+ GList *audio_track;
+ long audio_pos;
+ long audio_read_pos;
} Priv;
-//#define DISABLE_AUDIO
+static void
+clear_audio_track (GeglProperties *o)
+{
+ Priv *p = (Priv*)o->user_data;
+ while (p->audio_track)
+ {
+ g_free (p->audio_track->data);
+ p->audio_track = g_list_remove (p->audio_track, p->audio_track->data);
+ }
+}
+static void get_sample_data (Priv *p, long sample_no, float *left, float *right)
+{
+ int to_remove = 0;
+ GList *l;
+ l = p->audio_track;
+ if (sample_no < 0)
+ return;
+ for (; l; l = l->next)
+ {
+ AudioFrame *af = l->data;
+ if (sample_no > af->pos + af->len)
+ {
+ to_remove ++;
+ }
+
+ if (af->pos <= sample_no &&
+ sample_no < af->pos + af->len)
+ {
+ int i = sample_no - af->pos;
+ *left = af->data[0][i];
+ if (af->channels == 1)
+ *right = af->data[0][i];
+ else
+ *right = af->data[1][i];
+
+ if (to_remove) /* consuming audiotrack */
+ {
+ again:
+ for (l = p->audio_track; l; l = l->next)
+ {
+ AudioFrame *af = l->data;
+ if (sample_no > af->pos + af->len)
+ {
+ p->audio_track = g_list_remove (p->audio_track, af);
+ goto again;
+ }
+ }
+ }
+ return;
+ }
+ }
+ //fprintf (stderr, "didn't find audio sample\n");
+ *left = 0;
+ *right = 0;
+}
+
+#if 0
static void
buffer_open (GeglProperties *o, int size);
+#endif
static void
init (GeglProperties *o)
@@ -146,6 +220,10 @@ init (GeglProperties *o)
inited = 1;
}
+ clear_audio_track (o);
+ p->audio_pos = 0;
+ p->audio_read_pos = 0;
+
#ifndef DISABLE_AUDIO
//p->oxide_audio_instance = gggl_op_sym (op, "oxide_audio_instance");
//p->oxide_audio_query = gggl_op_sym (op, "oxide_audio_query()");
@@ -164,14 +242,14 @@ init (GeglProperties *o)
* provided fragment,. should be enough no matter how things are handled,
* but it should also be more than needed,. find out exact amount needed later
*/
-
+#if 0
if (!p->buffer)
{
int size =
(p->sample_rate / o->frame_rate) * p->channels * (p->bits / 8) * 2;
buffer_open (o, size);
}
-
+#endif
if (!p->fragment)
p->fragment = calloc (1, p->fragment_size);
}
@@ -192,180 +270,8 @@ static void write_audio_frame (GeglProperties *o,
AVFormatContext *oc,
AVStream *st);
-
-
-
#define STREAM_FRAME_RATE 25 /* 25 images/s */
-static int
-buffer_used (Priv * p)
-{
- int ret;
- if (!p || !p->buffer_size || !p->buffer)
- return -1;
-
- if (p->buffer_write_pos == p->buffer_read_pos)
- return 0;
- if (p->buffer_write_pos > p->buffer_read_pos)
- {
- ret = p->buffer_write_pos - p->buffer_read_pos;
- }
- else
- {
- ret = p->buffer_size - (p->buffer_read_pos - p->buffer_write_pos);
- }
- return ret;
-}
-
-static int
-buffer_unused (Priv * p)
-{
- int ret;
- ret = p->buffer_size - buffer_used (p) - 1; /* 1 byte for indicating full */
- return ret;
-}
-
-#ifndef DISABLE_AUDIO
-static void
-buffer_flush (Priv * p)
-{
- if (!p->buffer)
- return;
- p->buffer_write_pos = 0;
- p->buffer_read_pos = 0;
-}
-
-static void
-buffer_open (GeglProperties *o, int size)
-{
- Priv *p = (Priv*)o->user_data;
-
- if (p->buffer)
- {
- fprintf (stderr, "double init of buffer, eek!\n");
- }
-
- p->buffer_size = size;
- p->buffer = g_malloc (size);
- buffer_flush (p);
-}
-
-static void
-buffer_close (GeglProperties *o)
-{
- Priv *p = (Priv*)o->user_data;
-
- if (!p->buffer)
- return;
- g_free (p->buffer);
- p->buffer = NULL;
-}
-
-#endif
-
-static int
-buffer_write (Priv * p, uint8_t * source, int count)
-{
- int first_segment_size = 0;
- int second_segment_size = 0;
-
- /* check if we have room for the data in the buffer */
- if (!p->buffer || buffer_unused (p) < count + 1)
- {
- fprintf (stderr, "ff_save audio buffer full!! shouldn't happen\n");
- return -1;
- }
-
- /* calculate size of segments to write */
- first_segment_size = p->buffer_size - p->buffer_write_pos;
-
- if (p->buffer_read_pos > p->buffer_write_pos)
- first_segment_size = p->buffer_read_pos - p->buffer_write_pos;
-
- if (first_segment_size >= count)
- {
- first_segment_size = count;
- }
- else
- {
- second_segment_size = count - first_segment_size;
- }
-
- memcpy (p->buffer + p->buffer_write_pos, source, first_segment_size);
- p->buffer_write_pos += first_segment_size;
-
- if (p->buffer_write_pos == p->buffer_size)
- p->buffer_write_pos = 0;
-
- if (second_segment_size)
- {
- memcpy (p->buffer + p->buffer_write_pos, source + first_segment_size,
- second_segment_size);
- p->buffer_write_pos = second_segment_size;
- }
-
- return first_segment_size + second_segment_size;
-}
-
-#if 0
-. = unused byte
-# = used byte
- all sizes are specified in contiguous bytes of memory
- __write_pos / __read_pos
- //
- |................................... | empty buffer
- \ _________________________________ /
- size_ / __read_pos __write_pos / /|........
-#################..........|
- \ ______________ / used ()_ / __write_pos __read_pos / /|
-############..................#####|
- \______________ / unused ()_ / ___write_pos / __read_pos / /|
-#################.#################| full buffer
-#endif
- static int
- buffer_read (Priv * p, uint8_t * dest, int count)
-{
- int first_segment_size = 0;
- int second_segment_size = 0;
-
- /* check if we have enough data to fulfil request */
- if (!p->buffer || buffer_used (p) < count)
- {
- fprintf (stderr, "ff_save audio buffer doesn't have enough data\n");
- return -1;
- }
-
- /* calculate size of segments to write */
- first_segment_size = p->buffer_size - p->buffer_read_pos;
-
- if (p->buffer_write_pos > p->buffer_read_pos)
- first_segment_size = p->buffer_write_pos - p->buffer_read_pos;
-
- if (first_segment_size >= count)
- {
- first_segment_size = count;
- }
- else
- {
- second_segment_size = count - first_segment_size;
- }
-
- memcpy (dest, p->buffer + p->buffer_read_pos, first_segment_size);
- p->buffer_read_pos += first_segment_size;
-
- if (p->buffer_read_pos == p->buffer_size)
- p->buffer_read_pos = 0;
-
- if (second_segment_size)
- {
- memcpy (dest + first_segment_size, p->buffer + p->buffer_read_pos,
- second_segment_size);
- p->buffer_read_pos = second_segment_size;
- }
-
- return first_segment_size + second_segment_size;
-}
-
#ifndef DISABLE_AUDIO
/* add an audio output stream */
static AVStream *
@@ -413,10 +319,26 @@ open_audio (Priv * p, AVFormatContext * oc, AVStream * st)
c->bit_rate = 64000;
c->sample_fmt = codec->sample_fmts ? codec->sample_fmts[0] : AV_SAMPLE_FMT_FLTP;
+ if(1)if (codec->sample_fmts) {
+ int i;
+ for (i = 0; codec->sample_fmts[i]; i++)
+ {
+ if (codec->sample_fmts[i] == AV_SAMPLE_FMT_FLT)
+ fprintf (stderr, "supports interleaved float!\n");
+ if (codec->sample_fmts[i] == AV_SAMPLE_FMT_S16)
+ fprintf (stderr, "supports interleaved s16!\n");
+ if (codec->sample_fmts[i] == AV_SAMPLE_FMT_S16P)
+ fprintf (stderr, "supports planar s16!\n");
+ if (codec->sample_fmts[i] == AV_SAMPLE_FMT_FLTP)
+ fprintf (stderr, "supports planar float!\n");
+ }
+ }
+
c->sample_rate = 44100;
c->channel_layout = AV_CH_LAYOUT_STEREO;
c->channels = 2;
+
if (codec->supported_samplerates)
{
c->sample_rate = codec->supported_samplerates[0];
@@ -438,35 +360,38 @@ open_audio (Priv * p, AVFormatContext * oc, AVStream * st)
p->audio_outbuf_size = 10000;
p->audio_outbuf = malloc (p->audio_outbuf_size);
-#if 0
-
- /* ugly hack for PCM codecs (will be removed ASAP with new PCM
- support to compute the input frame size in samples */
- if (c->frame_size <= 1)
- {
- fprintf (stderr, "eeko\n");
- p->audio_input_frame_size = p->audio_outbuf_size / c->channels;
- switch (st->codec->codec_id)
- {
- case CODEC_ID_PCM_S16LE:
- case CODEC_ID_PCM_S16BE:
- case CODEC_ID_PCM_U16LE:
- case CODEC_ID_PCM_U16BE:
- p->audio_input_frame_size >>= 1;
- break;
- default:
- break;
- }
- }
- else
- {
- p->audio_input_frame_size = c->frame_size;
- }
- /*audio_input_frame_size = 44100/25;*/
-#endif
p->samples = malloc (p->audio_input_frame_size * 2 * c->channels);
}
+
+/* XXX: rewrite */
+static AVFrame *alloc_audio_frame(enum AVSampleFormat sample_fmt,
+ uint64_t channel_layout,
+ int sample_rate, int nb_samples)
+{
+ AVFrame *frame = av_frame_alloc();
+ int ret;
+
+ if (!frame) {
+ fprintf(stderr, "Error allocating an audio frame\n");
+ exit(1);
+ }
+
+ frame->format = sample_fmt;
+ frame->channel_layout = channel_layout;
+ frame->sample_rate = sample_rate;
+ frame->nb_samples = nb_samples;
+
+ if (nb_samples) {
+ ret = av_frame_get_buffer(frame, 0);
+ if (ret < 0) {
+ fprintf(stderr, "Error allocating an audio buffer\n");
+ exit(1);
+ }
+ }
+ return frame;
+}
+
void
write_audio_frame (GeglProperties *o, AVFormatContext * oc, AVStream * st)
{
@@ -476,8 +401,71 @@ write_audio_frame (GeglProperties *o, AVFormatContext * oc, AVStream * st)
AVPacket pkt;
av_init_packet (&pkt);
+ /* first we add incoming frames audio samples */
+ {
+ int i;
+ AudioFrame *af = g_malloc0 (sizeof (AudioFrame));
+ af->channels = 2; //o->audio->channels;
+ af->len = o->audio->samples;
+ for (i = 0; i < af->len; i++)
+ {
+ af->data[0][i] = o->audio->left[i];
+ af->data[1][i] = o->audio->right[i];
+ }
+ af->pos = p->audio_pos;
+ p->audio_pos += af->len;
+ p->audio_track = g_list_append (p->audio_track, af);
+ }
+
+ /* then we encode as much as we can in a loop using the codec frame size */
c = st->codec;
+
+ fprintf (stderr, "%li %i %i\n",
+ p->audio_pos, p->audio_read_pos, c->frame_size);
+ while (p->audio_pos - p->audio_read_pos > c->frame_size)
+ {
+ long i;
+ AVFrame *frame = alloc_audio_frame (c->sample_fmt, c->channel_layout,
+ c->sample_rate, c->frame_size);
+
+ for (i = 0; i < c->frame_size; i++)
+ {
+ float left = 0, right = 0;
+ get_sample_data (p, i + p->audio_read_pos, &left, &right);
+// fprintf (stderr, "[%f %f]\n", left, right);
+ }
+
+ av_frame_free (&frame);
+ p->audio_read_pos += c->frame_size;
+ }
+
+#if 0
+ if(1)switch (c->sample_fmt)
+ {
+ case AV_SAMPLE_FMT_FLT:
+ fprintf (stderr, "f\n");
+ break;
+ case AV_SAMPLE_FMT_FLTP:
+ fprintf (stderr, "fp\n");
+ break;
+ case AV_SAMPLE_FMT_S16:
+ fprintf (stderr, "s16\n");
+ break;
+ case AV_SAMPLE_FMT_S16P:
+ fprintf (stderr, "s16p\n");
+ break;
+ case AV_SAMPLE_FMT_S32:
+ case AV_SAMPLE_FMT_S32P:
+ fprintf (stderr, "s32\n");
+ break;
+ }
+#endif
+ //fprintf (stderr, "asdfasdfadf\n");
+
+ fprintf (stderr, "audio codec wants: %i samples\n", c->frame_size);
+ p->audio_input_frame_size = c->frame_size;
+ //fprintf (stderr, "going to grab %i %i\n", p->fragment_size, o->audio->samples);
#if 0
if (p->oxide_audio_get_fragment (p->oxide_audio_instance,
p->fragment) == (signed) p->fragment_size)
@@ -486,6 +474,7 @@ write_audio_frame (GeglProperties *o, AVFormatContext * oc, AVStream * st)
}
#endif
+#if 0
while (buffer_used (p) >= p->audio_input_frame_size * 2 * c->channels)
{
buffer_read (p, (uint8_t *) p->samples,
@@ -505,6 +494,7 @@ write_audio_frame (GeglProperties *o, AVFormatContext * oc, AVStream * st)
exit (1);
}
}
+#endif
}
/*p->audio_get_frame (samples, audio_input_frame_size, c->channels);*/
@@ -903,8 +893,9 @@ finalize (GObject *object)
if (o->user_data)
{
Priv *p = (Priv*)o->user_data;
-
+#if 0
buffer_close (o);
+#endif
if (p->oc)
{
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]