mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-03-28 11:55:39 +00:00
gst/mpegaudioparse/gstmpegaudioparse.c: Use GST_BOILERPLATE instead of manual GType magic.
Original commit message from CVS: * gst/mpegaudioparse/gstmpegaudioparse.c: (gst_mp3parse_base_init), (gst_mp3parse_init): Use GST_BOILERPLATE instead of manual GType magic. * gst/mpegaudioparse/gstmpegaudioparse.c: (gst_mp3parse_handle_first_frame), (mp3parse_time_to_bytepos), (mp3parse_bytepos_to_time): * gst/mpegaudioparse/gstmpegaudioparse.h: Implement seeking, byte->time, time->byte conversions with the Xing seek table if available. This allows better at least a bit more accurate seeks and file position reporting.
This commit is contained in:
parent
79cfc89c8f
commit
376b414679
3 changed files with 77 additions and 35 deletions
13
ChangeLog
13
ChangeLog
|
@ -1,3 +1,16 @@
|
|||
2007-07-01 Sebastian Dröge <slomo@circular-chaos.org>
|
||||
|
||||
* gst/mpegaudioparse/gstmpegaudioparse.c: (gst_mp3parse_base_init),
|
||||
(gst_mp3parse_init):
|
||||
Use GST_BOILERPLATE instead of manual GType magic.
|
||||
* gst/mpegaudioparse/gstmpegaudioparse.c:
|
||||
(gst_mp3parse_handle_first_frame), (mp3parse_time_to_bytepos),
|
||||
(mp3parse_bytepos_to_time):
|
||||
* gst/mpegaudioparse/gstmpegaudioparse.h:
|
||||
Implement seeking, byte->time, time->byte conversions with the Xing
|
||||
seek table if available. This allows better at least a bit more
|
||||
accurate seeks and file position reporting.
|
||||
|
||||
2007-06-28 Sebastian Dröge <slomo@circular-chaos.org>
|
||||
|
||||
* gst/mpegaudioparse/gstmpegaudioparse.c:
|
||||
|
|
|
@ -71,8 +71,9 @@ enum
|
|||
|
||||
|
||||
static void gst_mp3parse_class_init (GstMPEGAudioParseClass * klass);
|
||||
static void gst_mp3parse_base_init (GstMPEGAudioParseClass * klass);
|
||||
static void gst_mp3parse_init (GstMPEGAudioParse * mp3parse);
|
||||
static void gst_mp3parse_base_init (gpointer klass);
|
||||
static void gst_mp3parse_init (GstMPEGAudioParse * mp3parse,
|
||||
GstMPEGAudioParseClass * klass);
|
||||
|
||||
static gboolean gst_mp3parse_sink_event (GstPad * pad, GstEvent * event);
|
||||
static GstFlowReturn gst_mp3parse_chain (GstPad * pad, GstBuffer * buffer);
|
||||
|
@ -95,33 +96,9 @@ static gboolean mp3parse_bytepos_to_time (GstMPEGAudioParse * mp3parse,
|
|||
static gboolean
|
||||
mp3parse_total_bytes (GstMPEGAudioParse * mp3parse, gint64 * total);
|
||||
|
||||
static GstElementClass *parent_class = NULL;
|
||||
|
||||
/*static guint gst_mp3parse_signals[LAST_SIGNAL] = { 0 }; */
|
||||
|
||||
GType
|
||||
gst_mp3parse_get_type (void)
|
||||
{
|
||||
static GType mp3parse_type = 0;
|
||||
|
||||
if (!mp3parse_type) {
|
||||
static const GTypeInfo mp3parse_info = {
|
||||
sizeof (GstMPEGAudioParseClass),
|
||||
(GBaseInitFunc) gst_mp3parse_base_init,
|
||||
NULL,
|
||||
(GClassInitFunc) gst_mp3parse_class_init,
|
||||
NULL,
|
||||
NULL,
|
||||
sizeof (GstMPEGAudioParse),
|
||||
0,
|
||||
(GInstanceInitFunc) gst_mp3parse_init,
|
||||
};
|
||||
|
||||
mp3parse_type = g_type_register_static (GST_TYPE_ELEMENT,
|
||||
"GstMPEGAudioParse", &mp3parse_info, 0);
|
||||
}
|
||||
return mp3parse_type;
|
||||
}
|
||||
GST_BOILERPLATE (GstMPEGAudioParse, gst_mp3parse, GstElement, GST_TYPE_ELEMENT);
|
||||
|
||||
static guint mp3types_bitrates[2][3][16] = {
|
||||
{
|
||||
|
@ -225,7 +202,7 @@ mp3_caps_create (guint layer, guint channels, guint bitrate, guint samplerate)
|
|||
}
|
||||
|
||||
static void
|
||||
gst_mp3parse_base_init (GstMPEGAudioParseClass * klass)
|
||||
gst_mp3parse_base_init (gpointer klass)
|
||||
{
|
||||
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
|
||||
|
||||
|
@ -289,7 +266,7 @@ gst_mp3parse_reset (GstMPEGAudioParse * mp3parse)
|
|||
}
|
||||
|
||||
static void
|
||||
gst_mp3parse_init (GstMPEGAudioParse * mp3parse)
|
||||
gst_mp3parse_init (GstMPEGAudioParse * mp3parse, GstMPEGAudioParseClass * klass)
|
||||
{
|
||||
mp3parse->sinkpad =
|
||||
gst_pad_new_from_static_template (&mp3_sink_template, "sink");
|
||||
|
@ -609,10 +586,41 @@ gst_mp3parse_handle_first_frame (GstMPEGAudioParse * mp3parse)
|
|||
mp3parse->xing_bytes = 0;
|
||||
|
||||
if (xing_flags & XING_TOC_FLAG) {
|
||||
int i, percent = 0;
|
||||
guchar *table = mp3parse->xing_seek_table;
|
||||
|
||||
/* xing seek table: percent time -> 1/256 bytepos */
|
||||
memcpy (mp3parse->xing_seek_table, data, 100);
|
||||
|
||||
/* build inverse table: 1/256 bytepos -> 1/100 percent time */
|
||||
for (i = 0; i < 256; i++) {
|
||||
while (percent < 99 && table[percent + 1] <= i)
|
||||
percent++;
|
||||
|
||||
if (table[percent] == i) {
|
||||
mp3parse->xing_seek_table_inverse[i] = percent * 100;
|
||||
} else if (table[percent] < i && percent < 99) {
|
||||
gdouble fa, fb, fx;
|
||||
gint a = percent, b = percent + 1;
|
||||
|
||||
fa = table[a];
|
||||
fb = table[b];
|
||||
fx = (b - a) / (fb - fa) * (i - fa) + a;
|
||||
mp3parse->xing_seek_table_inverse[i] = (guint16) (fx * 100);
|
||||
} else if (percent == 98 && table[percent + 1] <= i) {
|
||||
gdouble fa, fb, fx;
|
||||
gint a = percent + 1, b = 100;
|
||||
|
||||
fa = table[a];
|
||||
fb = 256.0;
|
||||
fx = (b - a) / (fb - fa) * (i - fa) + a;
|
||||
mp3parse->xing_seek_table_inverse[i] = (guint16) (fx * 100);
|
||||
}
|
||||
}
|
||||
data += 100;
|
||||
} else {
|
||||
memset (mp3parse->xing_seek_table, 0, 100);
|
||||
memset (mp3parse->xing_seek_table_inverse, 0, 256);
|
||||
}
|
||||
|
||||
if (xing_flags & XING_VBR_SCALE_FLAG) {
|
||||
|
@ -971,10 +979,8 @@ static gboolean
|
|||
mp3parse_time_to_bytepos (GstMPEGAudioParse * mp3parse, GstClockTime ts,
|
||||
gint64 * bytepos)
|
||||
{
|
||||
#if 0
|
||||
gint64 total_bytes;
|
||||
GstClockTime total_time;
|
||||
#endif
|
||||
|
||||
/* -1 always maps to -1 */
|
||||
if (ts == -1) {
|
||||
|
@ -982,9 +988,6 @@ mp3parse_time_to_bytepos (GstMPEGAudioParse * mp3parse, GstClockTime ts,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/* FIXME: this seems to yield worse results than seeking based on the average
|
||||
* bitrate */
|
||||
#if 0
|
||||
/* If XING seek table exists use this for time->byte conversion */
|
||||
if ((mp3parse->xing_flags & XING_TOC_FLAG) &&
|
||||
mp3parse_total_bytes (mp3parse, &total_bytes) &&
|
||||
|
@ -1005,7 +1008,6 @@ mp3parse_time_to_bytepos (GstMPEGAudioParse * mp3parse, GstClockTime ts,
|
|||
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mp3parse->avg_bitrate == 0)
|
||||
goto no_bitrate;
|
||||
|
@ -1022,6 +1024,9 @@ static gboolean
|
|||
mp3parse_bytepos_to_time (GstMPEGAudioParse * mp3parse,
|
||||
gint64 bytepos, GstClockTime * ts)
|
||||
{
|
||||
gint64 total_bytes;
|
||||
GstClockTime total_time;
|
||||
|
||||
if (bytepos == -1) {
|
||||
*ts = GST_CLOCK_TIME_NONE;
|
||||
return TRUE;
|
||||
|
@ -1032,6 +1037,27 @@ mp3parse_bytepos_to_time (GstMPEGAudioParse * mp3parse,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/* If XING seek table exists use this for byte->time conversion */
|
||||
if ((mp3parse->xing_flags & XING_TOC_FLAG) &&
|
||||
mp3parse_total_bytes (mp3parse, &total_bytes) &&
|
||||
mp3parse_total_time (mp3parse, &total_time)) {
|
||||
gdouble fa, fb, fx;
|
||||
gdouble pos = CLAMP ((bytepos * 256.0) / total_bytes, 0.0, 256.0);
|
||||
gint index = CLAMP (pos, 0, 255);
|
||||
|
||||
fa = mp3parse->xing_seek_table_inverse[index];
|
||||
if (index < 255)
|
||||
fb = mp3parse->xing_seek_table_inverse[index + 1];
|
||||
else
|
||||
fb = 10000.0;
|
||||
|
||||
fx = fa + (fb - fa) * (pos - index);
|
||||
|
||||
*ts = (1.0 / 10000.0) * fx * total_time;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Cannot convert anything except 0 if we don't have a bitrate yet */
|
||||
if (mp3parse->avg_bitrate == 0)
|
||||
return FALSE;
|
||||
|
|
|
@ -79,7 +79,10 @@ struct _GstMPEGAudioParse {
|
|||
guint32 xing_frames;
|
||||
GstClockTime xing_total_time;
|
||||
guint32 xing_bytes;
|
||||
/* percent -> filepos mapping */
|
||||
guchar xing_seek_table[100];
|
||||
/* filepos -> percent mapping */
|
||||
guint16 xing_seek_table_inverse[256];
|
||||
guint32 xing_vbr_scale;
|
||||
guint xing_bitrate;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue