summaryrefslogtreecommitdiffstats
path: root/gst/mpeg1sys
diff options
context:
space:
mode:
Diffstat (limited to 'gst/mpeg1sys')
-rw-r--r--gst/mpeg1sys/.gitignore7
-rw-r--r--gst/mpeg1sys/Makefile.am13
-rw-r--r--gst/mpeg1sys/buffer.c482
-rw-r--r--gst/mpeg1sys/buffer.h141
-rw-r--r--gst/mpeg1sys/gstmpeg1systemencode.c572
-rw-r--r--gst/mpeg1sys/gstmpeg1systemencode.h110
-rw-r--r--gst/mpeg1sys/main.h140
-rw-r--r--gst/mpeg1sys/systems.c290
8 files changed, 1755 insertions, 0 deletions
diff --git a/gst/mpeg1sys/.gitignore b/gst/mpeg1sys/.gitignore
new file mode 100644
index 00000000..08f5ed37
--- /dev/null
+++ b/gst/mpeg1sys/.gitignore
@@ -0,0 +1,7 @@
+Makefile
+Makefile.in
+*.o
+*.lo
+*.la
+.deps
+.libs
diff --git a/gst/mpeg1sys/Makefile.am b/gst/mpeg1sys/Makefile.am
new file mode 100644
index 00000000..5e28e2be
--- /dev/null
+++ b/gst/mpeg1sys/Makefile.am
@@ -0,0 +1,13 @@
+filterdir = $(libdir)/gst
+
+filter_LTLIBRARIES = libgstmpeg1systemencode.la
+
+libgstmpeg1systemencode_la_SOURCES = gstmpeg1systemencode.c \
+ buffer.c \
+ systems.c
+
+noinst_HEADERS = gstmpeg1systemencode.h \
+ main.h \
+ buffer.h
+
+libsystem_encode_la_CFLAGS = -O2 $(FOMIT_FRAME_POINTER) -funroll-all-loops -finline-functions -ffast-math $(GST_CFLAGS)
diff --git a/gst/mpeg1sys/buffer.c b/gst/mpeg1sys/buffer.c
new file mode 100644
index 00000000..933b76e6
--- /dev/null
+++ b/gst/mpeg1sys/buffer.c
@@ -0,0 +1,482 @@
+/* Gnome-Streamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+
+/*#define DEBUG_ENABLED */
+#include <gst/gst.h>
+#include <libs/getbits/gstgetbits.h>
+
+#include "buffer.h"
+
+#define SEQUENCE_HEADER 0x000001b3
+#define SEQUENCE_END 0x000001b7
+#define PICTURE_START 0x00000100
+#define GROUP_START 0x000001b8
+#define SYNCWORD_START 0x000001
+
+#define AUDIO_SYNCWORD 0xfff
+
+#define CLOCKS 90000.0
+
+#define DEBUG(a, b...) g_print (##b)
+
+/* This must match decoder and encoder tables */
+static double picture_rates [16] =
+{
+ 0.0,
+ 24000.0/1001.,
+ 24.0,
+ 25.0,
+ 30000.0/1001.,
+ 30.0,
+ 50.0,
+ 60000.0/1001.,
+ 60.0,
+
+ 1,
+ 5,
+ 10,
+ 12,
+ 15,
+ 0,
+ 0
+};
+
+static double ratio [16] = { 0., 1., 0.6735, 0.7031, 0.7615, 0.8055,
+ 0.8437, 0.8935, 0.9157, 0.9815, 1.0255, 1.0695, 1.0950, 1.1575,
+ 1.2015, 0.};
+
+static char picture_types [4][3] =
+ { "I", "P", "B", "D" };
+
+static int bitrate_index[2][3][16] =
+{ { {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, },
+ {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, },
+ {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, } },
+ { {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, },
+ {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, },
+ {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, } },
+};
+
+static long frequency[9] =
+{44100, 48000, 32000, 22050, 24000, 16000, 11025, 12000, 8000};
+
+static double dfrequency[9] =
+{44.1, 48, 32, 22.05, 24, 16, 11.025, 12, 8};
+
+static unsigned int samples [4] = {192, 384, 1152, 1152};
+
+static char mode [4][15] =
+ { "stereo", "joint stereo", "dual channel", "single channel" };
+static char copyright [2][20] =
+ { "no copyright","copyright protected" };
+static char original [2][10] =
+ { "copy","original" };
+static char emphasis [4][20] =
+ { "none", "50/15 microseconds", "reserved", "CCITT J.17" };
+
+static void mpeg1mux_buffer_update_video_info(Mpeg1MuxBuffer *mb);
+static void mpeg1mux_buffer_update_audio_info(Mpeg1MuxBuffer *mb);
+
+Mpeg1MuxBuffer *mpeg1mux_buffer_new(guchar type, guchar id) {
+ Mpeg1MuxBuffer *new = g_malloc(sizeof(Mpeg1MuxBuffer));
+
+ new->buffer = NULL;
+ new->length = 0;
+ new->base = 0;
+ new->buffer_type = type;
+ new->stream_id = id;
+ new->scan_pos = 0;
+ new->new_frame = TRUE;
+ new->current_start = 0;
+ new->timecode_list = NULL;
+ new->queued_list = NULL;
+ new->next_frame_time = 0;
+
+ return new;
+}
+
+void mpeg1mux_buffer_queue(Mpeg1MuxBuffer *mb, GstBuffer *buf) {
+
+ if (mb->buffer == NULL) {
+ mb->buffer = g_malloc(GST_BUFFER_SIZE(buf));
+ mb->length = GST_BUFFER_SIZE(buf);
+ memcpy(mb->buffer, GST_BUFFER_DATA(buf), GST_BUFFER_SIZE(buf));
+ }
+ else {
+ mb->buffer = g_realloc(mb->buffer, mb->length + GST_BUFFER_SIZE(buf));
+ memcpy(mb->buffer+mb->length, GST_BUFFER_DATA(buf), GST_BUFFER_SIZE(buf));
+ mb->length += GST_BUFFER_SIZE(buf);
+ }
+
+ GST_DEBUG (0,"queuing buffer %lu\n", mb->length);
+ if (mb->buffer_type == BUFFER_TYPE_VIDEO) {
+ mpeg1mux_buffer_update_video_info(mb);
+ }
+ else {
+ mpeg1mux_buffer_update_audio_info(mb);
+ }
+}
+
+gulong mpeg1mux_buffer_update_queued(Mpeg1MuxBuffer *mb, guint64 scr) {
+ GList *queued_list;
+ Mpeg1MuxTimecode *tc;
+ gulong total_queued = 0;
+
+ GST_DEBUG (0,"queued in buffer on SCR=%llu\n", scr);
+ queued_list = g_list_first(mb->queued_list);
+
+ while (queued_list) {
+ tc = (Mpeg1MuxTimecode *) queued_list->data;
+ if (tc->DTS < scr) {
+ /* this buffer should be sent out */
+ mb->queued_list = g_list_remove(mb->queued_list, tc);
+ queued_list = g_list_first(mb->queued_list);
+ }
+ else {
+ GST_DEBUG (0,"queued in buffer %ld, %llu\n", tc->original_length, tc->DTS);
+ total_queued += tc->original_length;
+ queued_list = g_list_next(queued_list);
+ }
+ }
+ GST_DEBUG (0,"queued in buffer %lu\n", total_queued);
+
+ return total_queued;
+}
+
+void mpeg1mux_buffer_shrink(Mpeg1MuxBuffer *mb, gulong size) {
+ GList *timecode_list;
+ Mpeg1MuxTimecode *tc;
+ gulong consumed = 0;
+ gulong count;
+
+ GST_DEBUG (0,"shrinking buffer %lu\n", size);
+
+ g_assert(mb->length >= size);
+
+ memcpy(mb->buffer, mb->buffer+size, mb->length-size);
+ mb->buffer = g_realloc(mb->buffer, mb->length-size);
+
+ mb->length -= size;
+ mb->scan_pos -= size;
+ mb->current_start -= size;
+
+ timecode_list = g_list_first(mb->timecode_list);
+ tc = (Mpeg1MuxTimecode *) timecode_list->data;
+
+ if (tc->length > size) {
+ tc->length -= size;
+ mb->new_frame = FALSE;
+ }
+ else {
+ consumed += tc->length;
+ while (size >= consumed) {
+ GST_DEBUG (0,"removing timecode: %llu %llu %lu %lu\n", tc->DTS, tc->PTS, tc->length, consumed);
+ mb->timecode_list = g_list_remove_link(mb->timecode_list, timecode_list);
+ mb->queued_list = g_list_append(mb->queued_list, tc);
+ timecode_list = g_list_first(mb->timecode_list);
+ tc = (Mpeg1MuxTimecode *) timecode_list->data;
+ consumed += tc->length;
+ GST_DEBUG (0,"next timecode: %llu %llu %lu %lu\n", tc->DTS, tc->PTS, tc->length, consumed);
+ }
+ mb->new_frame = TRUE;
+ GST_DEBUG (0,"leftover frame size from %lu to %lu \n", tc->length, consumed-size);
+ tc->length = consumed - size;
+ }
+
+ if (mb->buffer_type == BUFFER_TYPE_VIDEO) {
+ mb->info.video.DTS = tc->DTS;
+ mb->info.video.PTS = tc->PTS;
+ mb->next_frame_time = tc->DTS;
+ }
+ else {
+ mb->info.audio.PTS = tc->PTS;
+ mb->next_frame_time = tc->PTS;
+ }
+ GST_DEBUG (0,"next frame time timecode: %llu %lu\n", mb->next_frame_time, tc->length);
+
+ /* check buffer consistency */
+ timecode_list = g_list_first(mb->timecode_list);
+ count = 0;
+
+ while (timecode_list) {
+ tc = (Mpeg1MuxTimecode *) timecode_list->data;
+ count += tc->length;
+
+ timecode_list = g_list_next(timecode_list);
+ }
+
+ if (count != mb->current_start) g_print("********** error %lu != %lu\n", count, mb->current_start);
+
+ mb->base += size;
+}
+
+static void mpeg1mux_buffer_update_video_info(Mpeg1MuxBuffer *mb) {
+ gboolean have_sync = FALSE;
+ guchar *data = mb->buffer;
+ gulong offset = mb->scan_pos;
+ guint sync_zeros = 0;
+ gulong id=0;
+ guint temporal_reference, temp;
+ gst_getbits_t gb;
+
+
+ GST_DEBUG (0,"mpeg1mux::update_video_info %lu %lu\n", mb->base, mb->scan_pos);
+ if (mb->base == 0 && mb->scan_pos == 0) {
+ if ((SYNCWORD_START<<8)+*(mb->buffer+3) == SEQUENCE_HEADER) {
+
+ gst_getbits_init(&gb, NULL, NULL);
+ gst_getbits_newbuf(&gb, data+4, mb->length);
+ mb->info.video.horizontal_size = gst_getbits12(&gb);
+ mb->info.video.vertical_size = gst_getbits12(&gb);
+ mb->info.video.aspect_ratio = gst_getbits4(&gb);
+ mb->info.video.picture_rate = gst_getbits4(&gb);
+ mb->info.video.bit_rate = gst_getbits18(&gb);
+ if (gst_getbits1(&gb) != 1) {
+ g_print("mpeg1mux::update_video_info: marker bit error\n");
+ }
+ mb->info.video.vbv_buffer_size = gst_getbits10(&gb);
+ mb->info.video.CSPF = gst_getbits1(&gb);
+
+ mb->info.video.secs_per_frame = 1. / picture_rates[mb->info.video.picture_rate];
+ mb->info.video.decoding_order=0;
+ mb->info.video.group_order=0;
+ GST_DEBUG (0,"mpeg1mux::update_video_info: secs per frame %g\n", mb->info.video.secs_per_frame);
+ }
+ else {
+ g_print("mpeg1mux::update_video_info: Invalid MPEG Video header\n");
+ }
+ }
+ while (offset < mb->length-6) {
+ if (!have_sync) {
+ guchar byte = *(data+offset);
+ /*GST_DEBUG (0,"mpeg1mux::update_video_info: found #%d at %lu\n",byte,offset); */
+ offset++;
+ /* if it's zero, increment the zero count */
+ if (byte == 0) {
+ sync_zeros++;
+ /*GST_DEBUG (0,"mpeg1mux::update_video_info: found zero #%d at %lu\n",sync_zeros,offset-1); */
+ }
+ /* if it's a one and we have two previous zeros, we have sync */
+ else if ((byte == 1) && (sync_zeros >= 2)) {
+ GST_DEBUG (0,"mpeg1mux::update_video_info: synced at %lu\n",offset-1);
+ have_sync = TRUE;
+ sync_zeros = 0;
+ }
+ /* if it's anything else, we've lost it completely */
+ else sync_zeros = 0;
+ /* then snag the chunk ID */
+ } else if (id == 0) {
+ id = *(data+offset);
+ GST_DEBUG (0,"mpeg1mux::update_video_info: got id 0x%02lX\n",id);
+ id = (SYNCWORD_START<<8)+id;
+ switch (id) {
+ case SEQUENCE_HEADER:
+ GST_DEBUG (0,"mpeg1mux::update_video_info: sequence header\n");
+ break;
+ case GROUP_START:
+ GST_DEBUG (0,"mpeg1mux::update_video_info: group start\n");
+ mb->info.video.group_order=0;
+ break;
+ case PICTURE_START:
+ /* skip the first access unit */
+ if (mb->info.video.decoding_order != 0) {
+ Mpeg1MuxTimecode *tc;
+ GST_DEBUG (0,"mpeg1mux::update_video_info: PTS %llu, DTS %llu, length %lu\n", mb->info.video.current_PTS,
+ mb->info.video.current_DTS, offset - mb->current_start-3);
+
+ tc = (Mpeg1MuxTimecode *) g_malloc(sizeof(Mpeg1MuxTimecode));
+ tc->length = offset - mb->current_start-3;
+ tc->original_length = tc->length;
+ tc->frame_type = mb->info.video.current_type;
+ tc->DTS = mb->info.video.current_DTS;
+ tc->PTS = mb->info.video.current_PTS;
+
+ mb->timecode_list = g_list_append(mb->timecode_list, tc);
+
+ if (mb->info.video.decoding_order == 0) {
+ mb->next_frame_time = tc->DTS;
+ }
+
+ mb->current_start = offset-3;
+ }
+
+ temp= (*(data+offset+1)<<8)+*(data+offset+2);
+ temporal_reference = (temp & 0xffc0) >> 6;
+ mb->info.video.current_type = (temp & 0x0038) >> 3;
+ GST_DEBUG (0,"mpeg1mux::update_video_info: picture start temporal_ref:%d type:%s Frame\n", temporal_reference,
+ picture_types[mb->info.video.current_type-1]);
+
+ mb->info.video.current_DTS = mb->info.video.decoding_order * mb->info.video.secs_per_frame * CLOCKS;
+ mb->info.video.current_PTS = (temporal_reference - mb->info.video.group_order + 1 +
+ mb->info.video.decoding_order) *mb->info.video.secs_per_frame*CLOCKS;
+
+ mb->info.video.decoding_order++;
+ mb->info.video.group_order++;
+
+
+ offset++;
+ break;
+ case SEQUENCE_END:
+ GST_DEBUG (0,"mpeg1mux::update_video_info: sequence end\n");
+ break;
+ }
+ /* prepare for next sync */
+ offset++;
+ have_sync = FALSE;
+ id = 0;
+ sync_zeros = 0;
+ }
+ }
+ mb->scan_pos = offset;
+}
+
+static void mpeg1mux_buffer_update_audio_info(Mpeg1MuxBuffer *mb) {
+ guchar *data = mb->buffer;
+ gulong offset = mb->scan_pos;
+ gulong id=0;
+ guint padding_bit;
+ gst_getbits_t gb;
+ guint startup_delay = 0;
+ int layer_index,lsf,samplerate_index,padding;
+ long bpf;
+ Mpeg1MuxTimecode *tc;
+
+
+ GST_DEBUG (0,"mpeg1mux::update_audio_info %lu %lu\n", mb->base, mb->scan_pos);
+ if (mb->base == 0 && mb->scan_pos == 0) {
+ id = GULONG_FROM_BE(*((gulong *)(data)));
+
+ printf("MPEG audio id = %08lx\n", id);
+ if ((id & 0xfff00000) == AUDIO_SYNCWORD<<20) {
+
+ /*mpegver = (header >> 19) & 0x3; // don't need this for bpf */
+ layer_index = (id >> 17) & 0x3;
+ mb->info.audio.layer = 4 - layer_index;
+ lsf = (id & (1 << 20)) ? ((id & (1 << 19)) ? 0 : 1) : 1;
+ mb->info.audio.bit_rate = bitrate_index[lsf][mb->info.audio.layer - 1][((id >> 12) & 0xf)];
+ samplerate_index = (id >> 10) & 0x3;
+ padding = (id >> 9) & 0x1;
+
+ if (mb->info.audio.layer == 1) {
+ bpf = mb->info.audio.bit_rate * 12000;
+ bpf /= frequency[samplerate_index];
+ bpf = ((bpf + padding) << 2);
+ } else {
+ bpf = mb->info.audio.bit_rate * 144000;
+ bpf /= frequency[samplerate_index];
+ bpf += padding;
+ }
+ mb->info.audio.framesize = bpf;
+
+ GST_DEBUG (0,"mpeg1mux::update_audio_info: samples per second %d\n", samplerate_index);
+
+ gst_getbits_init(&gb, NULL, NULL);
+ gst_getbits_newbuf(&gb, data, mb->length);
+
+ gst_flushbitsn(&gb, 12);
+ if (gst_getbits1(&gb) != 1) {
+ g_print("mpeg1mux::update_audio_info: marker bit error\n");
+ }
+ gst_flushbitsn(&gb, 2);
+ mb->info.audio.protection = gst_getbits1(&gb);
+ gst_flushbitsn(&gb, 4);
+ mb->info.audio.frequency = gst_getbits2(&gb);
+ padding_bit = gst_getbits1(&gb);
+ gst_flushbitsn(&gb, 1);
+ mb->info.audio.mode = gst_getbits2(&gb);
+ mb->info.audio.mode_extension = gst_getbits2(&gb);
+ mb->info.audio.copyright = gst_getbits1(&gb);
+ mb->info.audio.original_copy = gst_getbits1(&gb);
+ mb->info.audio.emphasis = gst_getbits2(&gb);
+
+ GST_DEBUG (0,"mpeg1mux::update_audio_info: layer %d\n", mb->info.audio.layer);
+ GST_DEBUG (0,"mpeg1mux::update_audio_info: bit_rate %d\n", mb->info.audio.bit_rate);
+ GST_DEBUG (0,"mpeg1mux::update_audio_info: frequency %d\n", mb->info.audio.frequency);
+
+ mb->info.audio.samples_per_second = (double)dfrequency [mb->info.audio.frequency];
+
+ GST_DEBUG (0,"mpeg1mux::update_audio_info: samples per second %g\n", mb->info.audio.samples_per_second);
+
+ mb->info.audio.decoding_order=0;
+
+ tc = (Mpeg1MuxTimecode *) g_malloc(sizeof(Mpeg1MuxTimecode));
+ tc->length = mb->info.audio.framesize;
+ tc->original_length = tc->length;
+ tc->frame_type = FRAME_TYPE_AUDIO;
+
+ mb->info.audio.current_PTS = mb->info.audio.decoding_order * samples [mb->info.audio.layer] /
+ mb->info.audio.samples_per_second * 90. + startup_delay;
+
+ GST_DEBUG (0,"mpeg1mux::update_audio_info: PTS %llu, length %u\n", mb->info.audio.current_PTS, mb->info.audio.framesize);
+ tc->PTS = mb->info.audio.current_PTS;
+ tc->DTS = mb->info.audio.current_PTS;
+ mb->timecode_list = g_list_append(mb->timecode_list, tc);
+
+ mb->next_frame_time = tc->PTS;
+
+ mb->info.audio.decoding_order++;
+ offset += tc->length;
+ }
+ else {
+ g_print("mpeg1mux::update_audio_info: Invalid MPEG Video header\n");
+ }
+ }
+ while (offset < mb->length-4) {
+ id = GULONG_FROM_BE(*((gulong *)(data+offset)));
+
+ /*mpegver = (header >> 19) & 0x3; // don't need this for bpf */
+ layer_index = (id >> 17) & 0x3;
+ mb->info.audio.layer = 4 - layer_index;
+ lsf = (id & (1 << 20)) ? ((id & (1 << 19)) ? 0 : 1) : 1;
+ mb->info.audio.bit_rate = bitrate_index[lsf][mb->info.audio.layer - 1][((id >> 12) & 0xf)];
+ samplerate_index = (id >> 10) & 0x3;
+ padding = (id >> 9) & 0x1;
+
+ if (mb->info.audio.layer == 1) {
+ bpf = mb->info.audio.bit_rate * 12000;
+ bpf /= frequency[samplerate_index];
+ bpf = ((bpf + padding) << 2);
+ } else {
+ bpf = mb->info.audio.bit_rate * 144000;
+ bpf /= frequency[samplerate_index];
+ bpf += padding;
+ }
+ tc = (Mpeg1MuxTimecode *) g_malloc(sizeof(Mpeg1MuxTimecode));
+ tc->length = bpf;
+ tc->original_length = tc->length;
+ tc->frame_type = FRAME_TYPE_AUDIO;
+
+ mb->current_start = offset + bpf;
+
+ mb->info.audio.samples_per_second = (double)dfrequency [mb->info.audio.frequency];
+
+ mb->info.audio.current_PTS = (mb->info.audio.decoding_order * samples [mb->info.audio.layer]) /
+ mb->info.audio.samples_per_second * 90. ;
+
+ tc->DTS = tc->PTS = mb->info.audio.current_PTS;
+ GST_DEBUG (0,"mpeg1mux::update_audio_info: PTS %llu, %llu length %lu\n", mb->info.audio.current_PTS, tc->PTS, tc->length);
+ mb->timecode_list = g_list_append(mb->timecode_list, tc);
+
+ mb->info.audio.decoding_order++;
+ offset += tc->length;
+ }
+ mb->scan_pos = offset;
+}
diff --git a/gst/mpeg1sys/buffer.h b/gst/mpeg1sys/buffer.h
new file mode 100644
index 00000000..f3eba4f7
--- /dev/null
+++ b/gst/mpeg1sys/buffer.h
@@ -0,0 +1,141 @@
+/* Gnome-Streamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __BUFFER_H__
+#define __BUFFER_H__
+
+#include <gst/gst.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define MPEG1MUX_BUFFER_QUEUED(mb) (g_list_length((mb)->timecode_list))
+#define MPEG1MUX_BUFFER_SPACE(mb) ((mb)->length)
+#define MPEG1MUX_BUFFER_DATA(mb) ((mb)->buffer)
+#define MPEG1MUX_BUFFER_TYPE(mb) ((mb)->buffer)
+#define MPEG1MUX_BUFFER_FIRST_TIMECODE(mb) (g_list_first((mb)->timecode_list)->data)
+
+#define BUFFER_TYPE_VIDEO 1
+#define BUFFER_TYPE_AUDIO 2
+
+#define FRAME_TYPE_IFRAME 1
+#define FRAME_TYPE_BFRAME 2
+#define FRAME_TYPE_PFRAME 3
+#define FRAME_TYPE_AUDIO 4
+
+typedef struct _Mpeg1MuxBuffer Mpeg1MuxBuffer;
+typedef struct _Mpeg1MuxTimecode Mpeg1MuxTimecode;
+
+typedef struct video_struc /* Informationen ueber Video Stream */
+{
+ unsigned int stream_length ;
+ unsigned int num_sequence ;
+ unsigned int num_seq_end ;
+ unsigned int num_pictures ;
+ unsigned int num_groups ;
+ unsigned int num_frames[4] ;
+ unsigned int avg_frames[4] ;
+
+ unsigned int horizontal_size;
+ unsigned int vertical_size ;
+ unsigned int aspect_ratio ;
+ unsigned int picture_rate ;
+ unsigned int bit_rate ;
+ unsigned int comp_bit_rate ;
+ unsigned int vbv_buffer_size;
+ unsigned int CSPF ;
+
+ guint64 PTS;
+ guint64 DTS;
+
+ guint64 current_PTS;
+ guint64 current_DTS;
+ guchar current_type;
+
+ double secs_per_frame;
+ gulong group_order, decoding_order;
+} Video_struc;
+
+typedef struct audio_struc /* Informationen ueber Audio Stream */
+{
+ unsigned int stream_length ;
+ unsigned int num_syncword ;
+ unsigned int num_frames [2] ;
+ unsigned int framesize ;
+ unsigned int layer ;
+ unsigned int protection ;
+ unsigned int bit_rate ;
+ unsigned int frequency ;
+ unsigned int mode ;
+ unsigned int mode_extension ;
+ unsigned int copyright ;
+ unsigned int original_copy ;
+ unsigned int emphasis ;
+
+ guint64 PTS;
+
+ guint64 current_PTS;
+
+ double samples_per_second;
+ gulong decoding_order;
+} Audio_struc;
+
+struct _Mpeg1MuxTimecode {
+ gulong length;
+ gulong original_length;
+ guchar frame_type;
+ guint64 PTS;
+ guint64 DTS;
+};
+
+struct _Mpeg1MuxBuffer {
+ unsigned char *buffer;
+ gulong length;
+ gulong base;
+ gulong scan_pos;
+ gulong last_pos;
+ gulong current_start;
+ guchar buffer_type;
+ guchar stream_id;
+ gboolean new_frame;
+ guint64 next_frame_time;
+
+ union {
+ Video_struc video;
+ Audio_struc audio;
+ } info;
+
+ GList *timecode_list;
+ GList *queued_list;
+};
+
+Mpeg1MuxBuffer *mpeg1mux_buffer_new(guchar type, guchar id);
+
+void mpeg1mux_buffer_queue(Mpeg1MuxBuffer *mb, GstBuffer *buf);
+void mpeg1mux_buffer_shrink(Mpeg1MuxBuffer *mb, gulong size);
+gulong mpeg1mux_buffer_update_queued(Mpeg1MuxBuffer *mb, guint64 scr);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __BUFFER_H__ */
diff --git a/gst/mpeg1sys/gstmpeg1systemencode.c b/gst/mpeg1sys/gstmpeg1systemencode.c
new file mode 100644
index 00000000..d8927d0f
--- /dev/null
+++ b/gst/mpeg1sys/gstmpeg1systemencode.c
@@ -0,0 +1,572 @@
+/* Gnome-Streamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+/*#define DEBUG_ENABLED */
+#include "gstmpeg1systemencode.h"
+#include "main.h"
+
+/*#define GST_DEBUG(a, b...) g_print (##b) */
+
+/* elementfactory information */
+static GstElementDetails system_encode_details = {
+ "MPEG1 Multiplexer",
+ "Filter/Multiplexer/System",
+ "Multiplexes MPEG-1 Streams",
+ VERSION,
+ "Wim Taymans <wim.taymans@chello.be>",
+ "(C) 2000",
+};
+
+/* GstMPEG1SystemEncode signals and args */
+enum {
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum {
+ ARG_0,
+ /* FILL ME */
+};
+
+GST_PADTEMPLATE_FACTORY (src_factory,
+ "src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_CAPS_NEW (
+ "src_video",
+ "video/mpeg",
+ "mpegversion", GST_PROPS_INT (1),
+ "systemstream", GST_PROPS_BOOLEAN (TRUE)
+ )
+)
+GST_PADTEMPLATE_FACTORY (video_sink_factory,
+ "video_%02d",
+ GST_PAD_SINK,
+ GST_PAD_REQUEST,
+ GST_CAPS_NEW (
+ "sink_video",
+ "video/mpeg",
+ "mpegversion", GST_PROPS_INT (1),
+ "systemstream", GST_PROPS_BOOLEAN (FALSE)
+ )
+)
+
+GST_PADTEMPLATE_FACTORY (audio_sink_factory,
+ "audio_%02d",
+ GST_PAD_SINK,
+ GST_PAD_REQUEST,
+ GST_CAPS_NEW (
+ "sink_audio",
+ "audio/mp3",
+ NULL
+ )
+)
+
+static void gst_system_encode_class_init (GstMPEG1SystemEncodeClass *klass);
+static void gst_system_encode_init (GstMPEG1SystemEncode *system_encode);
+
+static GstPad* gst_system_encode_request_new_pad (GstElement *element, GstPadTemplate *templ,
+ const gchar *unused);
+static void gst_system_encode_chain (GstPad *pad, GstBuffer *buf);
+
+static void gst_system_encode_set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec);
+static void gst_system_encode_get_property (GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec);
+
+static GstElementClass *parent_class = NULL;
+/*static guint gst_system_encode_signals[LAST_SIGNAL] = { 0 }; */
+
+GType
+gst_mpeg1_system_encode_get_type (void)
+{
+ static GType system_encode_type = 0;
+
+ if (!system_encode_type) {
+ static const GTypeInfo system_encode_info = {
+ sizeof(GstMPEG1SystemEncodeClass),
+ NULL,
+ NULL,
+ (GClassInitFunc)gst_system_encode_class_init,
+ NULL,
+ NULL,
+ sizeof(GstMPEG1SystemEncode),
+ 0,
+ (GInstanceInitFunc)gst_system_encode_init,
+ NULL
+ };
+ system_encode_type = g_type_register_static(GST_TYPE_ELEMENT, "GstMPEG1SystemEncode", &system_encode_info, 0);
+ }
+ return system_encode_type;
+}
+
+static void
+gst_system_encode_class_init (GstMPEG1SystemEncodeClass *klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass*)klass;
+ gstelement_class = (GstElementClass*)klass;
+
+ parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
+
+ gobject_class->set_property = gst_system_encode_set_property;
+ gobject_class->get_property = gst_system_encode_get_property;
+
+ gstelement_class->request_new_pad = gst_system_encode_request_new_pad;
+}
+
+static void
+gst_system_encode_init (GstMPEG1SystemEncode *system_encode)
+{
+ system_encode->srcpad = gst_pad_new_from_template (
+ GST_PADTEMPLATE_GET (src_factory), "src");
+ gst_element_add_pad (GST_ELEMENT (system_encode), system_encode->srcpad);
+
+ system_encode->video_buffer = mpeg1mux_buffer_new (BUFFER_TYPE_VIDEO, 0xE0);
+ system_encode->audio_buffer = mpeg1mux_buffer_new (BUFFER_TYPE_AUDIO, 0xC0);
+ system_encode->have_setup = FALSE;
+ system_encode->mta = NULL;
+ system_encode->packet_size = 2048;
+ system_encode->lock = g_mutex_new();
+ system_encode->current_pack = system_encode->packets_per_pack = 3;
+ system_encode->video_delay_ms = 0;
+ system_encode->audio_delay_ms = 0;
+ system_encode->sectors_delay = 0;
+ system_encode->startup_delay = ~1;
+ system_encode->which_streams = 0;
+ system_encode->num_audio_pads = 0;
+ system_encode->num_video_pads = 0;
+ system_encode->pack = g_malloc (sizeof (Pack_struc));
+ system_encode->sys_header = g_malloc (sizeof (Sys_header_struc));
+ system_encode->sector = g_malloc (sizeof (Sector_struc));
+
+}
+
+static GstPad*
+gst_system_encode_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *unused)
+{
+ GstMPEG1SystemEncode *system_encode;
+ gchar *name = NULL;
+ GstPad *newpad;
+
+ g_return_val_if_fail (templ != NULL, NULL);
+
+ if (templ->direction != GST_PAD_SINK) {
+ g_warning ("system_encode: request pad that is not a SINK pad\n");
+ return NULL;
+ }
+ system_encode = GST_SYSTEM_ENCODE (element);
+
+ if (templ == GST_PADTEMPLATE_GET (audio_sink_factory)) {
+ name = g_strdup_printf ("audio_%02d", system_encode->num_audio_pads);
+ g_print ("%s\n", name);
+ newpad = gst_pad_new_from_template (templ, name);
+ gst_pad_set_element_private (newpad, GINT_TO_POINTER (system_encode->num_audio_pads));
+
+ system_encode->audio_pad[system_encode->num_audio_pads] = newpad;
+ system_encode->num_audio_pads++;
+ system_encode->which_streams |= STREAMS_AUDIO;
+ }
+ else if (templ == GST_PADTEMPLATE_GET (video_sink_factory)) {
+ name = g_strdup_printf ("video_%02d", system_encode->num_video_pads);
+ g_print ("%s\n", name);
+ newpad = gst_pad_new_from_template (templ, name);
+ gst_pad_set_element_private (newpad, GINT_TO_POINTER (system_encode->num_video_pads));
+
+ system_encode->video_pad[system_encode->num_video_pads] = newpad;
+ system_encode->num_video_pads++;
+ system_encode->which_streams |= STREAMS_VIDEO;
+ }
+ else {
+ g_warning ("system_encode: this is not our template!\n");
+ return NULL;
+ }
+
+ gst_pad_set_chain_function (newpad, gst_system_encode_chain);
+ gst_element_add_pad (GST_ELEMENT (system_encode), newpad);
+
+ return newpad;
+}
+
+/* return a list of all the highest prioripty streams */
+static GList*
+gst_system_encode_pick_streams (GList *mta, GstMPEG1SystemEncode *system_encode)
+{
+ guint64 lowest = ~1;
+
+ GST_DEBUG (0, "pick_streams: %lld, %lld\n", system_encode->video_buffer->next_frame_time,
+ system_encode->audio_buffer->next_frame_time);
+
+ if (system_encode->which_streams & STREAMS_VIDEO) {
+ if (system_encode->video_buffer->next_frame_time < lowest-system_encode->video_delay) {
+ lowest = system_encode->video_buffer->next_frame_time;
+ }
+ }
+ if (system_encode->which_streams & STREAMS_AUDIO) {
+ if (system_encode->audio_buffer->next_frame_time < lowest-system_encode->audio_delay) {
+ lowest = system_encode->audio_buffer->next_frame_time;
+ }
+ }
+
+ if (system_encode->which_streams & STREAMS_VIDEO) {
+ if (system_encode->video_buffer->next_frame_time == lowest) {
+ mta = g_list_append(mta, system_encode->video_buffer);
+ }
+ }
+ if (system_encode->which_streams & STREAMS_AUDIO) {
+ if (system_encode->audio_buffer->next_frame_time == lowest) {
+ mta = g_list_append(mta, system_encode->audio_buffer);
+ }
+ }
+ return mta;
+}
+
+static gboolean
+gst_system_encode_have_data (GstMPEG1SystemEncode *system_encode)
+{
+
+ if (system_encode->which_streams == (STREAMS_VIDEO | STREAMS_AUDIO)) {
+ if (MPEG1MUX_BUFFER_QUEUED(system_encode->audio_buffer) > 2 &&
+ MPEG1MUX_BUFFER_SPACE(system_encode->audio_buffer) > system_encode->packet_size*2 &&
+ MPEG1MUX_BUFFER_QUEUED(system_encode->video_buffer) > 2 &&
+ MPEG1MUX_BUFFER_SPACE(system_encode->video_buffer) > system_encode->packet_size*2) {
+ return TRUE;
+ }
+ }
+ if (system_encode->which_streams == STREAMS_VIDEO) {
+ if (MPEG1MUX_BUFFER_QUEUED(system_encode->video_buffer) > 2 &&
+ MPEG1MUX_BUFFER_SPACE(system_encode->video_buffer) > system_encode->packet_size*2) {
+ return TRUE;
+ }
+ }
+ if (system_encode->which_streams == STREAMS_VIDEO) {
+ if (MPEG1MUX_BUFFER_QUEUED(system_encode->audio_buffer) > 2 &&
+ MPEG1MUX_BUFFER_SPACE(system_encode->audio_buffer) > system_encode->packet_size*2) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static GList*
+gst_system_encode_update_mta (GstMPEG1SystemEncode *system_encode, GList *mta, gulong size)
+{
+ GList *streams = g_list_first(mta);
+ Mpeg1MuxBuffer *mb = (Mpeg1MuxBuffer *)streams->data;
+
+ GST_DEBUG (0,"system_encode::multiplex: update mta\n");
+
+ mpeg1mux_buffer_shrink(mb, size);
+
+ mta = g_list_remove(mta, mb);
+
+ return mta;
+}
+
+static void
+gst_system_setup_multiplex (GstMPEG1SystemEncode *system_encode)
+{
+ Mpeg1MuxTimecode *video_tc, *audio_tc;
+
+ system_encode->audio_buffer_size = 4*1024;
+ system_encode->video_buffer_size = 46*1024;
+ system_encode->bytes_output = 0;
+ system_encode->min_packet_data = system_encode->packet_size - PACK_HEADER_SIZE - SYS_HEADER_SIZE -
+ PACKET_HEADER_SIZE - AFTER_PACKET_LENGTH;
+ system_encode->max_packet_data = system_encode->packet_size - PACKET_HEADER_SIZE - AFTER_PACKET_LENGTH;
+
+ if (system_encode->which_streams & STREAMS_VIDEO) {
+ system_encode->video_rate = system_encode->video_buffer->info.video.bit_rate * 50;
+ }
+ else system_encode->video_rate = 0;
+ if (system_encode->which_streams & STREAMS_AUDIO)
+ system_encode->audio_rate = system_encode->audio_buffer->info.audio.bit_rate * 128;
+ else system_encode->audio_rate = 0;
+
+ system_encode->data_rate = system_encode->video_rate + system_encode->audio_rate;
+
+ system_encode->dmux_rate = ceil((double)(system_encode->data_rate) *
+ ((double)(system_encode->packet_size)/(double)(system_encode->min_packet_data) +
+ ((double)(system_encode->packet_size)/(double)(system_encode->max_packet_data) *
+ (double)(system_encode->packets_per_pack-1.))) / (double)(system_encode->packets_per_pack) );
+ system_encode->data_rate = ceil(system_encode->dmux_rate/50.)*50;
+
+ GST_DEBUG (0,"system_encode::multiplex: data_rate %u, video_rate: %u, audio_rate: %u\n", system_encode->data_rate,
+ system_encode->video_rate, system_encode->audio_rate);
+
+ system_encode->video_delay = (double)system_encode->video_delay_ms*(double)(CLOCKS/1000);
+ system_encode->audio_delay = (double)system_encode->audio_delay_ms*(double)(CLOCKS/1000);
+
+ system_encode->mux_rate = ceil(system_encode->dmux_rate/50.);
+ system_encode->dmux_rate= system_encode->mux_rate * 50.;
+
+ video_tc = MPEG1MUX_BUFFER_FIRST_TIMECODE(system_encode->video_buffer);
+ audio_tc = MPEG1MUX_BUFFER_FIRST_TIMECODE(system_encode->audio_buffer);
+
+ GST_DEBUG (0,"system_encode::video tc %lld, audio tc %lld:\n", video_tc->DTS, audio_tc->DTS);
+
+ system_encode->delay = ((double)system_encode->sectors_delay +
+ ceil((double)video_tc->length/(double)system_encode->min_packet_data) +
+ ceil((double)video_tc->length/(double)system_encode->min_packet_data )) *
+ (double)system_encode->packet_size/system_encode->dmux_rate*(double)CLOCKS;
+
+ system_encode->audio_delay += system_encode->delay;
+ system_encode->video_delay += system_encode->delay;
+
+ system_encode->audio_delay = 0;
+ system_encode->video_delay = 0;
+ system_encode->delay = 0;
+
+ GST_DEBUG (0,"system_encode::multiplex: delay %g, mux_rate: %lu\n", system_encode->delay, system_encode->mux_rate);
+}
+
+static void
+gst_system_encode_multiplex(GstMPEG1SystemEncode *system_encode)
+{
+ GList *streams;
+ Mpeg1MuxBuffer *mb = (Mpeg1MuxBuffer *)streams->data;
+ guchar timestamps;
+ guchar buffer_scale;
+ GstBuffer *outbuf;
+ Pack_struc *pack;
+ Sys_header_struc *sys_header;
+ Mpeg1MuxTimecode *tc;
+ gulong buffer_size, non_scaled_buffer_size, total_queued;
+ guint64 PTS, DTS;
+
+ g_mutex_lock(system_encode->lock);
+
+ while (gst_system_encode_have_data(system_encode)) {
+ GST_DEBUG (0,"system_encode::multiplex: multiplexing\n");
+
+ if (!system_encode->have_setup) {
+ gst_system_setup_multiplex(system_encode);
+ system_encode->have_setup = TRUE;
+ }
+
+ if (system_encode->mta == NULL) {
+ system_encode->mta = gst_system_encode_pick_streams(system_encode->mta, system_encode);
+ }
+ if (system_encode->mta == NULL) break;
+
+
+ system_encode->SCR = (guint64)(system_encode->bytes_output+LAST_SCR_BYTE_IN_PACK)*CLOCKS/system_encode->dmux_rate;
+
+
+ streams = g_list_first(system_encode->mta);
+ mb = (Mpeg1MuxBuffer *)streams->data;
+
+ if (system_encode->current_pack == system_encode->packets_per_pack) {
+ create_pack(system_encode->pack, system_encode->SCR, system_encode->mux_rate);
+ create_sys_header (system_encode->sys_header, system_encode->mux_rate, 1, 1, 1, 1, 1, 1,
+ AUDIO_STR_0, 0, system_encode->audio_buffer_size/128,
+ VIDEO_STR_0, 1, system_encode->video_buffer_size/1024, system_encode->which_streams );
+ system_encode->current_pack = 0;
+ pack = system_encode->pack;
+ sys_header = system_encode->sys_header;
+ }
+ else {
+ system_encode->current_pack++;
+ pack = NULL;
+ sys_header = NULL;
+ }
+
+ tc = MPEG1MUX_BUFFER_FIRST_TIMECODE(mb);
+ if (mb->new_frame) {
+ GST_DEBUG (0,"system_encode::multiplex: new frame\n");
+ if (tc->frame_type == FRAME_TYPE_AUDIO || tc->frame_type == FRAME_TYPE_IFRAME || tc->frame_type == FRAME_TYPE_PFRAME) {
+ timestamps = TIMESTAMPS_PTS;
+ }
+ else {
+ timestamps = TIMESTAMPS_PTS_DTS;
+ }
+ }
+ else {
+ timestamps = TIMESTAMPS_NO;
+ }
+
+ if (tc->frame_type != FRAME_TYPE_AUDIO) {
+ if (tc->PTS<system_encode->startup_delay)
+ system_encode->startup_delay = tc->PTS;
+ }
+
+ if (tc->frame_type == FRAME_TYPE_AUDIO) {
+ buffer_scale = 0;
+ non_scaled_buffer_size = system_encode->audio_buffer_size;
+ buffer_size = system_encode->audio_buffer_size/128;
+ PTS = tc->PTS + system_encode->audio_delay + system_encode->startup_delay;
+ DTS = tc->PTS + system_encode->audio_delay + system_encode->startup_delay;
+ }
+ else {
+ buffer_scale = 1;
+ non_scaled_buffer_size = system_encode->video_buffer_size;
+ buffer_size = system_encode->video_buffer_size/1024;
+ PTS = tc->PTS + system_encode->video_delay;
+ DTS = tc->DTS + system_encode->video_delay;
+ }
+
+ total_queued = mpeg1mux_buffer_update_queued(mb, system_encode->SCR);
+
+ if (non_scaled_buffer_size - total_queued >= system_encode->packet_size) {
+
+ /* write the pack/packet here */
+ create_sector (system_encode->sector, pack, sys_header,
+ system_encode->packet_size,
+ MPEG1MUX_BUFFER_DATA(mb), mb->stream_id, buffer_scale,
+ buffer_size, TRUE, PTS, DTS,
+ timestamps, system_encode->which_streams);
+ /* update mta */
+ system_encode->mta = gst_system_encode_update_mta(system_encode, system_encode->mta,
+ system_encode->sector->length_of_packet_data);
+ }
+ else {
+ /* write a padding packet */
+ create_sector (system_encode->sector, pack, sys_header,
+ system_encode->packet_size, NULL, PADDING_STR, 0,
+ 0, FALSE, 0, 0,
+ TIMESTAMPS_NO, system_encode->which_streams);
+ }
+
+ outbuf = gst_buffer_new();
+ GST_BUFFER_DATA(outbuf) = g_malloc(system_encode->sector->length_of_sector);
+ GST_BUFFER_SIZE(outbuf) = system_encode->sector->length_of_sector;
+ memcpy(GST_BUFFER_DATA(outbuf),system_encode->sector->buf, system_encode->sector->length_of_sector);
+ system_encode->bytes_output += GST_BUFFER_SIZE(outbuf);
+ gst_pad_push(system_encode->srcpad,outbuf);
+
+ GST_DEBUG (0,"system_encode::multiplex: writing %02x\n", mb->stream_id);
+
+ }
+ gst_info("system_encode::multiplex: data left in video buffer %lu\n", MPEG1MUX_BUFFER_SPACE(system_encode->video_buffer));
+ gst_info("system_encode::multiplex: data left in audio buffer %lu\n", MPEG1MUX_BUFFER_SPACE(system_encode->audio_buffer));
+
+ g_mutex_unlock(system_encode->lock);
+}
+
+static void
+gst_system_encode_chain (GstPad *pad, GstBuffer *buf)
+{
+ GstMPEG1SystemEncode *system_encode;
+ guchar *data;
+ gulong size;
+ const gchar *padname;
+ gint channel;
+
+ g_return_if_fail(pad != NULL);
+ g_return_if_fail(GST_IS_PAD(pad));
+ g_return_if_fail(buf != NULL);
+
+ system_encode = GST_SYSTEM_ENCODE (GST_OBJECT_PARENT (pad));
+ data = GST_BUFFER_DATA(buf);
+ size = GST_BUFFER_SIZE(buf);
+
+ GST_DEBUG (0,"system_encode::chain: system_encode: have buffer of size %lu\n",size);
+ padname = GST_OBJECT_NAME (pad);
+
+ if (strncmp(padname, "audio_", 6) == 0) {
+ channel = atoi(&padname[6]);
+ GST_DEBUG (0,"gst_system_encode_chain: got audio buffer in from audio channel %02d\n", channel);
+
+ mpeg1mux_buffer_queue(system_encode->audio_buffer, buf);
+ }
+ else if (strncmp(padname, "video_", 6) == 0) {
+ channel = atoi(&padname[6]);
+ GST_DEBUG (0,"gst_system_encode_chain: got video buffer in from video channel %02d\n", channel);
+
+ mpeg1mux_buffer_queue(system_encode->video_buffer, buf);
+
+ }
+ else {
+ g_assert_not_reached ();
+ }
+ gst_system_encode_multiplex(system_encode);
+
+ gst_buffer_unref(buf);
+}
+
+static void
+gst_system_encode_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ GstMPEG1SystemEncode *system_encode;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail(GST_IS_SYSTEM_ENCODE(object));
+ system_encode = GST_SYSTEM_ENCODE(object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_system_encode_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ GstMPEG1SystemEncode *src;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail(GST_IS_SYSTEM_ENCODE(object));
+ src = GST_SYSTEM_ENCODE(object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static gboolean
+plugin_init (GModule *module, GstPlugin *plugin)
+{
+ GstElementFactory *factory;
+
+ /* this filter needs the getbits functions */
+ if (!gst_library_load("gstgetbits")) {
+ gst_info("system_encode:: could not load support library: 'gstgetbits'\n");
+ return FALSE;
+ }
+
+ /* create an elementfactory for the system_encode element */
+ factory = gst_elementfactory_new("system_encode",GST_TYPE_SYSTEM_ENCODE,
+ &system_encode_details);
+ g_return_val_if_fail(factory != NULL, FALSE);
+
+ gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (src_factory));
+ gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (audio_sink_factory));
+ gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (video_sink_factory));
+
+ gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
+
+ return TRUE;
+}
+
+GstPluginDesc plugin_desc = {
+ GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "system_encode",
+ plugin_init
+};
diff --git a/gst/mpeg1sys/gstmpeg1systemencode.h b/gst/mpeg1sys/gstmpeg1systemencode.h
new file mode 100644
index 00000000..bb24f01d
--- /dev/null
+++ b/gst/mpeg1sys/gstmpeg1systemencode.h
@@ -0,0 +1,110 @@
+/* Gnome-Streamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __SYSTEM_ENCODE_H__
+#define __SYSTEM_ENCODE_H__
+
+
+#include <config.h>
+#include <gst/gst.h>
+#include <libs/getbits/gstgetbits.h>
+
+#include "buffer.h"
+#include "main.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define GST_TYPE_SYSTEM_ENCODE \
+ (gst_mpeg1_system_encode_get_type())
+#define GST_SYSTEM_ENCODE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SYSTEM_ENCODE,GstMPEG1SystemEncode))
+#define GST_SYSTEM_ENCODE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SYSTEM_ENCODE,GstMPEG1SystemEncode))
+#define GST_IS_SYSTEM_ENCODE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SYSTEM_ENCODE))
+#define GST_IS_SYSTEM_ENCODE_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SYSTEM_ENCODE))
+
+typedef struct _GstMPEG1SystemEncode GstMPEG1SystemEncode;
+typedef struct _GstMPEG1SystemEncodeClass GstMPEG1SystemEncodeClass;
+
+struct _GstMPEG1SystemEncode {
+ GstElement element;
+
+ GstPad *srcpad;
+
+ gboolean have_setup;
+
+ GMutex *lock;
+
+ guint num_audio_pads;
+ guint num_video_pads;
+
+ Mpeg1MuxBuffer *audio_buffer;
+ Mpeg1MuxBuffer *video_buffer;
+
+ Pack_struc *pack;
+ Sys_header_struc *sys_header;
+ Sector_struc *sector;
+
+ guint data_rate, video_rate, audio_rate;
+ gdouble delay, audio_delay, video_delay;
+ gdouble clock_cycles;
+ gulong sectors_delay, video_delay_ms, audio_delay_ms;
+ gulong startup_delay;
+ gulong audio_buffer_size;
+ gulong video_buffer_size;
+ gulong mux_rate, dmux_rate;
+ guint64 SCR;
+ gint which_streams;
+
+ gint current_pack;
+ gulong min_packet_data;
+ gulong max_packet_data;
+ gint packets_per_pack;
+ gulong packet_size;
+ gulong bytes_output;
+
+ GList *mta;
+
+ /* stream input pads */
+ GstPad *private_1_pad[8]; /* up to 8 ac3 audio tracks <grumble> */
+ GstPad *private_2_pad;
+ GstPad *video_pad[16];
+ GstPad *audio_pad[32];
+};
+
+struct _GstMPEG1SystemEncodeClass {
+ GstElementClass parent_class;
+};
+
+GType gst_mpeg1_system_encode_get_type(void);
+
+/* multplex.c */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __SYSTEM_ENCODE_H__ */
diff --git a/gst/mpeg1sys/main.h b/gst/mpeg1sys/main.h
new file mode 100644
index 00000000..434f57f5
--- /dev/null
+++ b/gst/mpeg1sys/main.h
@@ -0,0 +1,140 @@
+/*************************************************************************
+* Generating a MPEG/SYSTEMS *
+* MULTIPLEXED VIDEO/AUDIO STREAM *
+* from two MPEG source streams *
+* Christoph Moar *
+* SIEMENS CORPORATE RESEARCH AND DEVELOPMENT ST SN 11 / T SN 6 *
+* (C) 1994 1995 *
+**************************************************************************
+* Restrictions apply. Will not support the whole MPEG/SYSTEM Standard. *
+* Basically, will generate Constrained System Parameter Files. *
+* Mixes only one audio and/or one video stream. Might be expanded. *
+*************************************************************************/
+
+/*************************************************************************
+* mplex - MPEG/SYSTEMS multiplexer *
+* Copyright (C) 1994 1995 Christoph Moar *
+* Siemens ZFE ST SN 11 / T SN 6 *
+* *
+* moar@informatik.tu-muenchen.de *
+* (Christoph Moar) *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with this program; if not, write to the Free Software *
+* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
+*************************************************************************/
+
+
+#ifndef __MAIN_H__
+#define __MAIN_H__
+
+#include <glib.h>
+
+#define PACK_START 0x000001ba
+#define SYS_HEADER_START 0x000001bb
+#define ISO11172_END 0x000001b9
+#define PACKET_START 0x000001
+
+#define CLOCKS 90000.0 /* System Clock Hertz */
+
+#define AFTER_PACKET_LENGTH 15 /* No of non-data-bytes */
+ /* following the packet */
+ /* length field */
+#define LAST_SCR_BYTE_IN_PACK 9 /* No of bytes in pack */
+ /* preceding, and */
+ /* including, the SCR */
+
+/* The following values for sys_header_length & size are only valid for */
+/* System streams consisting of two basic streams. When wrapping around */
+/* the system layer on a single video or a single audio stream, those */
+/* values get decreased by 3. */
+
+#define SYS_HEADER_LENGTH 12 /* length of Sys Header */
+ /* after start code and */
+ /* length field */
+
+#define SYS_HEADER_SIZE 18 /* incl. start code and */
+ /* length field */
+#define PACK_HEADER_SIZE 12
+
+#define PACKET_HEADER_SIZE 6
+
+#define MAX_SECTOR_SIZE 0x20000 /* Max Sektor Groesse */
+
+#define STREAMS_VIDEO 1
+#define STREAMS_AUDIO 2
+#define STREAMS_BOTH 3
+
+#define AUDIO_STREAMS 0xb8 /* Marker Audio Streams */
+#define VIDEO_STREAMS 0xb9 /* Marker Video Streams */
+#define AUDIO_STR_0 0xc0 /* Marker Audio Stream0 */
+#define VIDEO_STR_0 0xe0 /* Marker Video Stream0 */
+#define PADDING_STR 0xbe /* Marker Padding Stream*/
+
+#define ZERO_STUFFING_BYTE 0
+#define STUFFING_BYTE 0xff
+#define RESERVED_BYTE 0xff
+#define TIMESTAMPS_NO 0 /* Flag NO timestamps */
+#define TIMESTAMPS_PTS 1 /* Flag PTS timestamp */
+#define TIMESTAMPS_PTS_DTS 2 /* Flag BOTH timestamps */
+
+#define MARKER_SCR 2 /* Marker SCR */
+#define MARKER_JUST_PTS 2 /* Marker only PTS */
+#define MARKER_PTS 3 /* Marker PTS */
+#define MARKER_DTS 1 /* Marker DTS */
+#define MARKER_NO_TIMESTAMPS 0x0f /* Marker NO timestamps */
+
+#define STATUS_AUDIO_END 0 /* Statusmessage A end */
+#define STATUS_VIDEO_END 1 /* Statusmessage V end */
+#define STATUS_AUDIO_TIME_OUT 2 /* Statusmessage A out */
+#define STATUS_VIDEO_TIME_OUT 3 /* Statusmessage V out */
+
+/*************************************************************************
+ Typ- und Strukturdefinitionen
+*************************************************************************/
+
+typedef struct sector_struc /* A sector, can contain pack, sys header */
+ /* and packet. */
+{ unsigned char buf [MAX_SECTOR_SIZE] ;
+ unsigned int length_of_sector ;
+ unsigned int length_of_packet_data ;
+ guint64 TS ;
+} Sector_struc;
+
+typedef struct pack_struc /* Pack Info */
+{ unsigned char buf [PACK_HEADER_SIZE];
+ guint64 SCR;
+} Pack_struc;
+
+typedef struct sys_header_struc /* System Header Info */
+{ unsigned char buf [SYS_HEADER_SIZE];
+} Sys_header_struc;
+
+/*************************************************************************
+ Funktionsprototypen, keine Argumente, K&R Style
+*************************************************************************/
+
+/* systems.c */
+void create_sector (Sector_struc *sector, Pack_struc *pack, Sys_header_struc *sys_header,
+ unsigned int packet_size, unsigned char *inputbuffer, unsigned char type, unsigned char buffer_scale,
+ unsigned int buffer_size, unsigned char buffers, guint64 PTS, guint64 DTS,
+ unsigned char timestamps, unsigned int which_streams);
+
+void create_pack (Pack_struc *pack, guint64 SCR, unsigned int mux_rate);
+
+void create_sys_header (Sys_header_struc *sys_header, unsigned int rate_bound, unsigned char audio_bound,
+ unsigned char fixed, unsigned char CSPS, unsigned char audio_lock, unsigned char video_lock,
+ unsigned char video_bound, unsigned char stream1, unsigned char buffer1_scale, unsigned int buffer1_size,
+ unsigned char stream2, unsigned char buffer2_scale, unsigned int buffer2_size, unsigned int which_streams);
+
+#endif
diff --git a/gst/mpeg1sys/systems.c b/gst/mpeg1sys/systems.c
new file mode 100644
index 00000000..d0b3388a
--- /dev/null
+++ b/gst/mpeg1sys/systems.c
@@ -0,0 +1,290 @@
+#include <string.h>
+
+#include "main.h"
+
+static void buffer_timecode (timecode, marker, buffer)
+guint64 timecode;
+unsigned char marker;
+unsigned char **buffer;
+
+{
+ unsigned char temp;
+
+ temp = (marker << 4) | ((timecode>>29) & 0x38) |
+ ((timecode >> 29) & 0x6) | 1;
+ *((*buffer)++)=temp;
+ temp = (timecode & 0x3fc00000) >> 22;
+ *((*buffer)++)=temp;
+ temp = ((timecode & 0x003f8000) >> 14) | 1;
+ *((*buffer)++)=temp;
+ temp = (timecode & 0x7f80) >> 7;
+ *((*buffer)++)=temp;
+ temp = ((timecode & 0x007f) << 1) | 1;
+ *((*buffer)++)=temp;
+}
+
+/*************************************************************************
+ creates a complete sector.
+ Also copies Pack and Sys_Header informations into the
+ sector buffer, then reads a packet full of data from
+ the input stream into the sector buffer.
+*************************************************************************/
+
+
+void create_sector (sector, pack, sys_header,
+ packet_size, inputbuffer, type,
+ buffer_scale, buffer_size, buffers,
+ PTS, DTS, timestamps, which_streams )
+
+Sector_struc *sector;
+Pack_struc *pack;
+Sys_header_struc *sys_header;
+unsigned int packet_size;
+unsigned char *inputbuffer;
+
+unsigned char type;
+unsigned char buffer_scale;
+unsigned int buffer_size;
+unsigned char buffers;
+guint64 PTS;
+guint64 DTS;
+unsigned char timestamps;
+unsigned int which_streams;
+
+{
+ int i,j,tmp;
+ unsigned char *index;
+ unsigned char *size_offset;
+
+ /* printf("creating sector\n"); */
+
+ index = sector->buf;
+ sector->length_of_sector=0;
+
+/* Should we copy Pack Header information ? */
+
+ if (pack != NULL)
+ {
+ i = sizeof(pack->buf);
+ bcopy (pack->buf, index, i);
+ index += i;
+ sector->length_of_sector += i;
+ }
+
+/* Should we copy System Header information ? */
+
+ if (sys_header != NULL)
+ {
+ i = sizeof(sys_header->buf);
+
+ /* only one stream? 3 bytes less in sys header */
+ if (which_streams != STREAMS_BOTH) i -= 3;
+
+ bcopy (sys_header->buf, index, i);
+ index += i;
+ sector->length_of_sector += i;
+ }
+
+ /* write constant packet header data */
+
+ *(index++) = (unsigned char)(PACKET_START)>>16;
+ *(index++) = (unsigned char)(PACKET_START & 0x00ffff)>>8;
+ *(index++) = (unsigned char)(PACKET_START & 0x0000ff);
+ *(index++) = type;
+
+ /* we remember this offset in case we will have to shrink this packet */
+
+ size_offset = index;
+ *(index++) = (unsigned char)((packet_size - PACKET_HEADER_SIZE)>>8);
+ *(index++) = (unsigned char)((packet_size - PACKET_HEADER_SIZE)&0xff);
+
+ *(index++) = STUFFING_BYTE;
+ *(index++) = STUFFING_BYTE;
+ *(index++) = STUFFING_BYTE;
+
+ i = 0;
+
+ if (!buffers) i +=2;
+ if (timestamps == TIMESTAMPS_NO) i+=9;
+ else if (timestamps == TIMESTAMPS_PTS) i+=5;
+
+ /* printf("%i stuffing %d\n", i, timestamps); */
+
+ for (j=0; j<i; j++)
+ *(index++) = STUFFING_BYTE;
+
+ /* should we write buffer info ? */
+
+ if (buffers)
+ {
+ *(index++) = (unsigned char) (0x40 |
+ (buffer_scale << 5) | (buffer_size >> 8));
+ *(index++) = (unsigned char) (buffer_size & 0xff);
+ }
+
+ /* should we write PTS, PTS & DTS or nothing at all ? */
+
+ switch (timestamps)
+ {
+ case TIMESTAMPS_NO:
+ *(index++) = MARKER_NO_TIMESTAMPS;
+ break;
+ case TIMESTAMPS_PTS:
+ buffer_timecode (PTS, MARKER_JUST_PTS, &index);
+ sector->TS = PTS;
+ break;
+ case TIMESTAMPS_PTS_DTS:
+ buffer_timecode (PTS, MARKER_PTS, &index);
+ buffer_timecode (DTS, MARKER_DTS, &index);
+ sector->TS = DTS;
+ break;
+ }
+
+/* read in packet data */
+
+ i = (packet_size - PACKET_HEADER_SIZE - AFTER_PACKET_LENGTH);
+
+ if (type == PADDING_STR)
+ {
+ for (j=0; j<i; j++)
+ *(index++)=(unsigned char) STUFFING_BYTE;
+ tmp = i;
+ }
+ else
+ {
+ /*tmp = fread (index, sizeof (unsigned char), i, inputstream);*/
+ memcpy(index, inputbuffer, i); tmp = i;
+ index += tmp;
+
+ /* if we did not get enough data bytes, shorten the Packet length */
+
+ if (tmp != i)
+ {
+ packet_size -= (i-tmp);
+ *(size_offset++) = (unsigned char)((packet_size - PACKET_HEADER_SIZE)>>8);
+ *(size_offset++) = (unsigned char)((packet_size - PACKET_HEADER_SIZE)&0xff);
+
+/* zero byte stuffing in the last Packet of a stream */
+/* we don't need this any more, since we shortenend the packet */
+/* for (j=tmp; j<i; j++) */
+/* *(index++)=(unsigned char) ZERO_STUFFING_BYTE; */
+ }
+ }
+
+
+ /* write other struct data */
+
+ sector->length_of_sector += packet_size;
+ sector->length_of_packet_data = tmp;
+
+}
+
+/*************************************************************************
+ writes specifical pack header information into a buffer
+ later this will be copied from the sector routine into
+ the sector buffer
+*************************************************************************/
+
+void create_pack (pack, SCR, mux_rate)
+
+Pack_struc *pack;
+unsigned int mux_rate;
+guint64 SCR;
+
+{
+ unsigned char *index;
+
+ index = pack->buf;
+
+ *(index++) = (unsigned char)((PACK_START)>>24);
+ *(index++) = (unsigned char)((PACK_START & 0x00ff0000)>>16);
+ *(index++) = (unsigned char)((PACK_START & 0x0000ff00)>>8);
+ *(index++) = (unsigned char)(PACK_START & 0x000000ff);
+ buffer_timecode (SCR, MARKER_SCR, &index);
+ *(index++) = (unsigned char)(0x80 | (mux_rate >>15));
+ *(index++) = (unsigned char)(0xff & (mux_rate >> 7));
+ *(index++) = (unsigned char)(0x01 | ((mux_rate & 0x7f)<<1));
+ pack->SCR = SCR;
+}
+
+
+/*************************************************************************
+ writes specifical system header information into a buffer
+ later this will be copied from the sector routine into
+ the sector buffer
+*************************************************************************/
+
+void create_sys_header (sys_header, rate_bound, audio_bound,
+ fixed, CSPS, audio_lock, video_lock,
+ video_bound,
+ stream1, buffer1_scale, buffer1_size,
+ stream2, buffer2_scale, buffer2_size,
+ which_streams)
+
+Sys_header_struc *sys_header;
+unsigned int rate_bound;
+unsigned char audio_bound;
+unsigned char fixed;
+unsigned char CSPS;
+unsigned char audio_lock;
+unsigned char video_lock;
+unsigned char video_bound;
+
+unsigned char stream1;
+unsigned char buffer1_scale;
+unsigned int buffer1_size;
+unsigned char stream2;
+unsigned char buffer2_scale;
+unsigned int buffer2_size;
+unsigned int which_streams;
+
+{
+ unsigned char *index;
+
+ index = sys_header->buf;
+
+ /* if we are not using both streams, we should clear some
+ options here */
+
+ if (!(which_streams & STREAMS_AUDIO))
+ audio_bound = 0;
+ if (!(which_streams & STREAMS_VIDEO))
+ video_bound = 0;
+
+ *(index++) = (unsigned char)((SYS_HEADER_START)>>24);
+ *(index++) = (unsigned char)((SYS_HEADER_START & 0x00ff0000)>>16);
+ *(index++) = (unsigned char)((SYS_HEADER_START & 0x0000ff00)>>8);
+ *(index++) = (unsigned char)(SYS_HEADER_START & 0x000000ff);
+
+ if (which_streams == STREAMS_BOTH) {
+ *(index++) = (unsigned char)(SYS_HEADER_LENGTH >> 8);
+ *(index++) = (unsigned char)(SYS_HEADER_LENGTH & 0xff);
+ } else {
+ *(index++) = (unsigned char)((SYS_HEADER_LENGTH-3) >> 8);
+ *(index++) = (unsigned char)((SYS_HEADER_LENGTH-3) & 0xff);
+ }
+
+ *(index++) = (unsigned char)(0x80 | (rate_bound >>15));
+ *(index++) = (unsigned char)(0xff & (rate_bound >> 7));
+ *(index++) = (unsigned char)(0x01 | ((rate_bound & 0x7f)<<1));
+ *(index++) = (unsigned char)((audio_bound << 2)|(fixed << 1)|CSPS);
+ *(index++) = (unsigned char)((audio_lock << 7)|
+ (video_lock << 6)|0x20|video_bound);
+
+ *(index++) = (unsigned char)RESERVED_BYTE;
+
+ if (which_streams & STREAMS_AUDIO) {
+ *(index++) = stream1;
+ *(index++) = (unsigned char) (0xc0 |
+ (buffer1_scale << 5) | (buffer1_size >> 8));
+ *(index++) = (unsigned char) (buffer1_size & 0xff);
+ }
+
+ if (which_streams & STREAMS_VIDEO) {
+ *(index++) = stream2;
+ *(index++) = (unsigned char) (0xc0 |
+ (buffer2_scale << 5) | (buffer2_size >> 8));
+ *(index++) = (unsigned char) (buffer2_size & 0xff);
+ }
+
+}