summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThibaut Mattern <thibaut.mattern@gmail.com>2008-01-10 01:12:27 +0100
committerThibaut Mattern <thibaut.mattern@gmail.com>2008-01-10 01:12:27 +0100
commitccba3fddb126be14200e2003186f25aaf91bec26 (patch)
tree8db77b38c79e2dfae74d6afc9390632dc4658a8b
parent2a9d1fe9f99cc2329a762f6e30a8ee0dc8e84014 (diff)
parent9a73bf70505fabfa0e96dec07f20337286270385 (diff)
downloadxine-lib-ccba3fddb126be14200e2003186f25aaf91bec26.tar.gz
xine-lib-ccba3fddb126be14200e2003186f25aaf91bec26.tar.bz2
Merge new flag.
-rw-r--r--src/demuxers/demux_mpgaudio.c96
-rw-r--r--src/demuxers/demux_wav.c14
-rw-r--r--src/libmad/xine_mad_decoder.c67
-rw-r--r--src/xine-engine/buffer.h7
-rw-r--r--src/xine-engine/metronom.c35
5 files changed, 148 insertions, 71 deletions
diff --git a/src/demuxers/demux_mpgaudio.c b/src/demuxers/demux_mpgaudio.c
index 8e716f095..17916f837 100644
--- a/src/demuxers/demux_mpgaudio.c
+++ b/src/demuxers/demux_mpgaudio.c
@@ -65,11 +65,13 @@
/* Xing header stuff */
#define XING_TAG FOURCC_TAG('X', 'i', 'n', 'g')
#define INFO_TAG FOURCC_TAG('I', 'n', 'f', 'o')
+#define LAME_TAG FOURCC_TAG('L', 'A', 'M', 'E')
#define XING_FRAMES_FLAG 0x0001
#define XING_BYTES_FLAG 0x0002
#define XING_TOC_FLAG 0x0004
#define XING_VBR_SCALE_FLAG 0x0008
#define XING_TOC_LENGTH 100
+#define LAME_HEADER_LENGTH 0xC0
/* Xing header stuff */
#define VBRI_TAG FOURCC_TAG('V', 'B', 'R', 'I')
@@ -96,6 +98,10 @@ typedef struct {
uint32_t stream_size;
uint8_t toc[XING_TOC_LENGTH];
uint32_t vbr_scale;
+
+ /* Lame extension */
+ uint16_t start_delay;
+ uint16_t end_delay;
} xing_header_t;
/* Vbri Vbr Header struct */
@@ -380,9 +386,21 @@ static xing_header_t* parse_xing_header(mpg_audio_frame_t *frame,
xing->vbr_scale = -1;
if (xing->flags & XING_VBR_SCALE_FLAG) {
if (ptr >= (buf + bufsize - 4)) goto exit_error;
- xing->vbr_scale = _X_BE_32(ptr);
+ xing->vbr_scale = _X_BE_32(ptr); ptr += 4;
lprintf("vbr_scale: %d\n", xing->vbr_scale);
}
+
+ /* LAME extension */
+ /* see http://gabriel.mp3-tech.org/mp3infotag.html */
+ ptr -= 0x9C; /* move offset to match LAME header specs */
+ if (ptr + LAME_HEADER_LENGTH >= (buf + bufsize - 4)) goto exit_error;
+ if (_X_BE_32(&ptr[0x9C]) == LAME_TAG) {
+ lprintf("Lame header found\n");
+ xing->start_delay = (ptr[0xb1] << 4) | (ptr[0xb2] >> 4);
+ xing->end_delay = ((ptr[0xb2] & 0x0f) << 4) | ptr[0xb3];
+ lprintf("start delay : %d samples\n", xing->start_delay);
+ lprintf("end delay : %d samples\n", xing->end_delay);
+ }
} else {
lprintf("Xing header not found\n");
}
@@ -537,7 +555,22 @@ static int parse_frame_payload(demux_mpgaudio_t *this,
buf->content = buf->mem;
buf->type = BUF_AUDIO_MPEG;
buf->decoder_info[0] = 1;
- buf->decoder_flags = decoder_flags|BUF_FLAG_FRAME_END;
+ buf->decoder_flags = decoder_flags | BUF_FLAG_FRAME_END;
+
+ /* send encoder padding */
+ if (this->xing_header) {
+ if (frame_pos == this->mpg_frame_start) {
+ lprintf("sending a start padding of %d samples.\n", this->xing_header->start_delay);
+ buf->decoder_flags = buf->decoder_flags | BUF_FLAG_AUDIO_PADDING;
+ buf->decoder_info[1] = this->xing_header->start_delay;
+ buf->decoder_info[2] = 0;
+ } else if ((frame_pos + this->cur_frame.size) == this->mpg_frame_end) {
+ lprintf("sending a end padding of %d samples.\n", this->xing_header->end_delay);
+ buf->decoder_flags = buf->decoder_flags | BUF_FLAG_AUDIO_PADDING;
+ buf->decoder_info[1] = 0;
+ buf->decoder_info[2] = this->xing_header->end_delay;
+ }
+ }
this->audio_fifo->put(this->audio_fifo, buf);
lprintf("send buffer: pts=%"PRId64"\n", pts);
@@ -613,31 +646,31 @@ static int demux_mpgaudio_next (demux_mpgaudio_t *this, int decoder_flags, int s
if (parse_frame_header(&this->cur_frame, header_buf)) {
- /* send header buffer */
- if ( send_header ) {
- buf_element_t *buf;
-
- buf = this->audio_fifo->buffer_pool_alloc(this->audio_fifo);
-
- buf->type = BUF_AUDIO_MPEG;
- buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAME_END;
-
- buf->decoder_info[0] = 0;
- buf->decoder_info[1] = this->cur_frame.freq;
- buf->decoder_info[2] = 0; /* bits_per_sample */
-
- /* Only for channel_mode == 3 (mono) there is one channel, for any other case, there are 2 */
- buf->decoder_info[3] = ( this->cur_frame.channel_mode == 3 ) ? 1 : 2;
-
- buf->size = 0; /* No extra header data */
-
- this->audio_fifo->put(this->audio_fifo, buf);
- }
-
+ /* send header buffer */
+ if ( send_header ) {
+ buf_element_t *buf;
+
+ buf = this->audio_fifo->buffer_pool_alloc(this->audio_fifo);
+
+ buf->type = BUF_AUDIO_MPEG;
+ buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAME_END;
+
+ buf->decoder_info[0] = 0;
+ buf->decoder_info[1] = this->cur_frame.freq;
+ buf->decoder_info[2] = 0; /* bits_per_sample */
+
+ /* Only for channel_mode == 3 (mono) there is one channel, for any other case, there are 2 */
+ buf->decoder_info[3] = ( this->cur_frame.channel_mode == 3 ) ? 1 : 2;
+
+ buf->size = 0; /* No extra header data */
+
+ this->audio_fifo->put(this->audio_fifo, buf);
+ }
+
return parse_frame_payload(this, header_buf, decoder_flags);
} else if ( id3v2_istag(header_buf) ) {
- if (!id3v2_parse_tag(this->input, this->stream, header_buf)) {
+ if (!id3v2_parse_tag(this->input, this->stream, header_buf)) {
xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
LOG_MODULE ": ID3V2 tag parsing error\n");
bytes = 1; /* resync */
@@ -660,9 +693,18 @@ static int demux_mpgaudio_send_chunk (demux_plugin_t *this_gen) {
demux_mpgaudio_t *this = (demux_mpgaudio_t *) this_gen;
- if (!demux_mpgaudio_next (this, 0, 0))
- this->status = DEMUX_FINISHED;
+ if (!demux_mpgaudio_next (this, 0, 0)) {
+ /* Hack: send 8 zero bytes to flush the libmad decoder */
+ buf_element_t *buf;
+ buf = this->audio_fifo->buffer_pool_alloc(this->audio_fifo);
+ buf->type = BUF_AUDIO_MPEG;
+ buf->decoder_flags = BUF_FLAG_FRAME_END;
+ buf->size = 8;
+ memset(buf->content, 0, buf->size);
+ this->audio_fifo->put(this->audio_fifo, buf);
+ this->status = DEMUX_FINISHED;
+ }
return this->status;
}
@@ -997,7 +1039,7 @@ static uint32_t demux_mpgaudio_get_capabilities(demux_plugin_t *this_gen) {
}
static int demux_mpgaudio_get_optional_data(demux_plugin_t *this_gen,
- void *data, int data_type) {
+ void *data, int data_type) {
return DEMUX_OPTIONAL_UNSUPPORTED;
}
diff --git a/src/demuxers/demux_wav.c b/src/demuxers/demux_wav.c
index 9b46336fe..33baaf973 100644
--- a/src/demuxers/demux_wav.c
+++ b/src/demuxers/demux_wav.c
@@ -64,6 +64,7 @@ typedef struct {
off_t data_start;
off_t data_size;
+ int send_newpts;
int seek_flag; /* this is set when a seek just occurred */
} demux_wav_t;
@@ -160,9 +161,9 @@ static int demux_wav_send_chunk(demux_plugin_t *this_gen) {
current_pts *= 90000;
current_pts /= this->wave->nAvgBytesPerSec;
- if (this->seek_flag) {
- _x_demux_control_newpts(this->stream, current_pts, BUF_FLAG_SEEK);
- this->seek_flag = 0;
+ if (this->send_newpts) {
+ _x_demux_control_newpts(this->stream, current_pts, this->seek_flag);
+ this->send_newpts = this->seek_flag = 0;
}
while (remaining_sample_bytes) {
@@ -258,10 +259,13 @@ static int demux_wav_seek (demux_plugin_t *this_gen,
start_pos = (off_t) ( (double) start_pos / 65535 *
this->data_size );
- this->seek_flag = 1;
this->status = DEMUX_OK;
- _x_demux_flush_engine (this->stream);
+ this->send_newpts = 1;
+ if (playing) {
+ this->seek_flag = 1;
+ _x_demux_flush_engine (this->stream);
+ }
/* if input is non-seekable, do not proceed with the rest of this
* seek function */
if (!INPUT_IS_SEEKABLE(this->input))
diff --git a/src/libmad/xine_mad_decoder.c b/src/libmad/xine_mad_decoder.c
index 2f6d7cfe3..bb4ba1f7a 100644
--- a/src/libmad/xine_mad_decoder.c
+++ b/src/libmad/xine_mad_decoder.c
@@ -70,6 +70,9 @@ typedef struct mad_decoder_s {
uint8_t buffer[INPUT_BUF_SIZE];
int bytes_in_buffer;
int preview_mode;
+ int start_padding;
+ int end_padding;
+ int needs_more_data;
} mad_decoder_t;
@@ -84,6 +87,9 @@ static void mad_reset (audio_decoder_t *this_gen) {
this->pts = 0;
this->bytes_in_buffer = 0;
this->preview_mode = 0;
+ this->start_padding = 0;
+ this->end_padding = 0;
+ this->needs_more_data = 0;
mad_synth_init (&this->synth);
mad_stream_init (&this->stream);
@@ -95,7 +101,7 @@ static void mad_reset (audio_decoder_t *this_gen) {
static void mad_discontinuity (audio_decoder_t *this_gen) {
mad_decoder_t *this = (mad_decoder_t *) this_gen;
-
+
this->pts = 0;
}
@@ -136,7 +142,7 @@ static void mad_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) {
mad_decoder_t *this = (mad_decoder_t *) this_gen;
- lprintf ("decode data, decoder_flags: %d\n", buf->decoder_flags);
+ lprintf ("decode data, decoder_flags: 0x%08X\n", buf->decoder_flags);
if (buf->size>(INPUT_BUF_SIZE-this->bytes_in_buffer)) {
xprintf (this->xstream->xine, XINE_VERBOSITY_DEBUG,
@@ -144,7 +150,7 @@ static void mad_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) {
buf->size, INPUT_BUF_SIZE-this->bytes_in_buffer);
buf->size = INPUT_BUF_SIZE-this->bytes_in_buffer;
}
-
+
if ((buf->decoder_flags & BUF_FLAG_HEADER) == 0) {
/* reset decoder on leaving preview mode */
@@ -167,6 +173,17 @@ static void mad_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) {
mad_stream_buffer (&this->stream, this->buffer,
this->bytes_in_buffer);
+ if (!this->needs_more_data) {
+ this->pts = buf->pts;
+ if (buf->decoder_flags & BUF_FLAG_AUDIO_PADDING) {
+ this->start_padding = buf->decoder_info[1];
+ this->end_padding = buf->decoder_info[2];
+ } else {
+ this->start_padding = 0;
+ this->end_padding = 0;
+ }
+ }
+
while (1) {
if (mad_frame_decode (&this->frame, &this->stream) != 0) {
@@ -184,6 +201,8 @@ static void mad_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) {
switch (this->stream.error) {
case MAD_ERROR_BUFLEN:
+ /* libmad wants more data */
+ this->needs_more_data = 1;
return;
default:
@@ -247,13 +266,14 @@ static void mad_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) {
mad_synth_frame (&this->synth, &this->frame);
if ( (buf->decoder_flags & BUF_FLAG_PREVIEW) == 0 ) {
-
+
unsigned int nchannels, nsamples;
mad_fixed_t const *left_ch, *right_ch;
struct mad_pcm *pcm = &this->synth.pcm;
audio_buffer_t *audio_buffer;
uint16_t *output;
+
audio_buffer = this->xstream->audio_out->get_buffer (this->xstream->audio_out);
output = audio_buffer->mem;
@@ -261,7 +281,24 @@ static void mad_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) {
nsamples = pcm->length;
left_ch = pcm->samples[0];
right_ch = pcm->samples[1];
-
+
+ /* padding */
+ if (this->start_padding || this->end_padding) {
+ /* check padding validity */
+ if (nsamples < (this->start_padding + this->end_padding)) {
+ lprintf("invalid padding data");
+ this->start_padding = 0;
+ this->end_padding = 0;
+ }
+ lprintf("nsamples=%d, start_padding=%d, end_padding=%d\n",
+ nsamples, this->start_padding, this->end_padding);
+ nsamples -= this->start_padding + this->end_padding;
+ left_ch += this->start_padding;
+ right_ch += this->start_padding;
+ }
+ audio_buffer->num_frames = nsamples;
+ audio_buffer->vpts = this->pts;
+
while (nsamples--) {
/* output sample(s) in 16-bit signed little-endian PCM */
@@ -272,19 +309,25 @@ static void mad_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) {
}
- audio_buffer->num_frames = pcm->length;
- audio_buffer->vpts = buf->pts;
+ lprintf ("audio_out->put_buffer, samples=%d, pts=%"PRId64"\n", audio_buffer->num_frames, audio_buffer->vpts);
this->xstream->audio_out->put_buffer (this->xstream->audio_out, audio_buffer, this->xstream);
+ this->pts = buf->pts;
buf->pts = 0;
-
+ if (buf->decoder_flags & BUF_FLAG_AUDIO_PADDING) {
+ this->start_padding = buf->decoder_info[1];
+ this->end_padding = buf->decoder_info[2];
+ buf->decoder_info[1] = 0;
+ buf->decoder_info[2] = 0;
+ } else {
+ this->start_padding = 0;
+ this->end_padding = 0;
+ }
}
-
- lprintf ("decode worked\n");
+ lprintf ("decode worked\n");
}
- }
-
+ }
}
}
diff --git a/src/xine-engine/buffer.h b/src/xine-engine/buffer.h
index 2bcc29510..3a3f06e9b 100644
--- a/src/xine-engine/buffer.h
+++ b/src/xine-engine/buffer.h
@@ -373,6 +373,13 @@ struct buf_element_s {
* decoder_info[2] carries denominator for display aspect ratio */
#define BUF_FLAG_ASPECT 0x0800
+/* Amount of audio padding added by encoder (mp3, aac). These empty
+ * audio frames are causing a gap when switching between mp3 files.
+ * decoder_info[1] carries amount of audio frames padded at the
+ * beginning of the buffer
+ * decoder_info[2] carries amount of audio frames padded at the end of
+ * the buffer */
+#define BUF_FLAG_AUDIO_PADDING 0x1000
/* Special buffer types:
* Sometimes there is a need to relay special information from a demuxer
diff --git a/src/xine-engine/metronom.c b/src/xine-engine/metronom.c
index 5d3e0a12d..5bf6495a2 100644
--- a/src/xine-engine/metronom.c
+++ b/src/xine-engine/metronom.c
@@ -305,6 +305,8 @@ static void metronom_handle_discontinuity (metronom_t *this, int type,
/* video_vpts and audio_vpts adjustements */
cur_time = this->xine->clock->get_current_time(this->xine->clock);
+ xprintf(this->xine, XINE_VERBOSITY_DEBUG,
+ "current time : %" PRId64 "\n", cur_time);
switch (type) {
case DISC_STREAMSTART:
@@ -321,33 +323,12 @@ static void metronom_handle_discontinuity (metronom_t *this, int type,
case DISC_ABSOLUTE:
case DISC_RELATIVE:
- if (this->video_vpts < cur_time) {
- /* still frame */
- if (this->audio_vpts > cur_time) {
- /* still frame with audio */
- this->video_vpts = this->audio_vpts;
- xprintf(this->xine, XINE_VERBOSITY_DEBUG, "video vpts adjusted to audio vpts %" PRId64 "\n", this->video_vpts);
- } else {
- /* still frame, no audio */
- this->video_vpts = this->prebuffer + cur_time;
- this->audio_vpts = this->video_vpts;
- this->audio_vpts_rmndr = 0;
- this->force_video_jump = 1;
- this->force_audio_jump = 1;
- this->video_drift = 0;
- xprintf(this->xine, XINE_VERBOSITY_DEBUG, "vpts adjusted with prebuffer to %" PRId64 "\n",
- this->video_vpts);
- }
+ if (this->video_vpts < this->audio_vpts) {
+ this->video_vpts = this->audio_vpts;
+ xprintf(this->xine, XINE_VERBOSITY_DEBUG, "video vpts adjusted to audio vpts %" PRId64 "\n", this->video_vpts);
} else {
- /* video */
- if (this->audio_vpts < cur_time) {
- /* video, no sound */
- this->audio_vpts = this->video_vpts;
- this->audio_vpts_rmndr = 0;
- xprintf(this->xine, XINE_VERBOSITY_DEBUG, "audio vpts adjusted to video vpts %" PRId64 "\n", this->video_vpts);
- } else {
- /* video + audio */
- }
+ this->audio_vpts = this->video_vpts;
+ xprintf(this->xine, XINE_VERBOSITY_DEBUG, "audio vpts adjusted to video vpts %" PRId64 "\n", this->video_vpts);
}
break;
}
@@ -373,7 +354,7 @@ static void metronom_handle_discontinuity (metronom_t *this, int type,
this->vpts_offset = this->video_vpts - disc_off;
break;
}
-
+
this->last_video_pts = 0;
this->last_audio_pts = 0;
}