python-mechanize: rename to include version, remove unneeded variables
[opendreambox.git] / meta-opendreambox / recipes-multimedia / gstreamer / gst-plugins-bad / 0002-add-indexing-capabilities-to-generate-a-SPN-PTS-map-.patch
1 From 0d5e73089dcf64398a4835d84c0dbcf77ef04e14 Mon Sep 17 00:00:00 2001
2 From: Andreas Frisch <fraxinas@opendreambox.org>
3 Date: Mon, 28 Mar 2011 10:31:23 +0200
4 Subject: [PATCH 2/3] add indexing capabilities to generate a SPN/PTS map on
5  the fly in m2ts-mode
6
7 ---
8  gst/mpegtsmux/mpegtsmux.c |  234 ++++++++++++++++++++++++++++++++++++++++++++-
9  gst/mpegtsmux/mpegtsmux.h |   13 +++
10  2 files changed, 243 insertions(+), 4 deletions(-)
11
12 diff --git a/gst/mpegtsmux/mpegtsmux.c b/gst/mpegtsmux/mpegtsmux.c
13 index a243e40..d5492a4 100644
14 --- a/gst/mpegtsmux/mpegtsmux.c
15 +++ b/gst/mpegtsmux/mpegtsmux.c
16 @@ -104,7 +104,8 @@
17    ARG_PROG_MAP,
18    ARG_M2TS_MODE,
19    ARG_PAT_INTERVAL,
20 -  ARG_PMT_INTERVAL
21 +  ARG_PMT_INTERVAL,
22 +  ARG_ALIGNMENT
23  };
24  
25  static GstStaticPadTemplate mpegtsmux_sink_factory =
26 @@ -157,6 +158,12 @@
27  static void mpegtsdemux_set_header_on_caps (MpegTsMux * mux);
28  static gboolean mpegtsmux_sink_event (GstPad * pad, GstEvent * event);
29  static gboolean mpegtsmux_src_event (GstPad * pad, GstEvent * event);
30 +static void mpegtsmux_set_index (GstElement * element, GstIndex * index);
31 +static GstIndex *mpegtsmux_get_index (GstElement * element);
32 +
33 +static GstFormat pts_format;
34 +static GstFormat spn_format;
35 +guint get_packets_per_buffer (MpegTsMux * mux);
36  
37  GST_BOILERPLATE (MpegTsMux, mpegtsmux, GstElement, GST_TYPE_ELEMENT);
38  
39 @@ -175,6 +182,10 @@
40        "MPEG Transport Stream Muxer", "Codec/Muxer",
41        "Multiplexes media streams into an MPEG Transport Stream",
42        "Fluendo <contact@fluendo.com>");
43 +
44 +  pts_format =
45 +      gst_format_register ("PTS", "MPEG System Presentation Time Stamp");
46 +  spn_format = gst_format_register ("SPN", "Source Packet Number");
47  }
48  
49  static void
50 @@ -191,6 +202,9 @@
51    gstelement_class->release_pad = mpegtsmux_release_pad;
52    gstelement_class->change_state = mpegtsmux_change_state;
53  
54 +  gstelement_class->set_index = GST_DEBUG_FUNCPTR (mpegtsmux_set_index);
55 +  gstelement_class->get_index = GST_DEBUG_FUNCPTR (mpegtsmux_get_index);
56 +
57    g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PROG_MAP,
58        g_param_spec_boxed ("prog-map", "Program map",
59            "A GstStructure specifies the mapping from elementary streams to programs",
60 @@ -213,6 +227,12 @@
61            "Set the interval (in ticks of the 90kHz clock) for writing out the PMT table",
62            1, G_MAXUINT, TSMUX_DEFAULT_PMT_INTERVAL,
63            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
64 +
65 +  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ALIGNMENT,
66 +      g_param_spec_uint ("alignment", "packet alignment",
67 +          "Queue this amount of ts/m2ts packets before pushing buffer. On EOS, pad with dummy packets until aligned. Default: 32 for m2ts streams, else disabled.",
68 +          0, G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
69 +
70  }
71  
72  static void
73 @@ -247,6 +267,15 @@
74    mux->streamheader_sent = FALSE;
75    mux->force_key_unit_event = NULL;
76    mux->pending_key_unit_ts = GST_CLOCK_TIME_NONE;
77 +
78 +  mux->spn_count = 0;
79 +
80 +  mux->element_index = NULL;
81 +  mux->element_index_writer_id = -1;
82 +
83 +  mux->arbitrary_align = FALSE;
84 +  mux->alignment_adapter = gst_adapter_new ();
85 +  mux->packets_per_buffer = 0;
86  }
87  
88  static void
89 @@ -288,6 +317,15 @@
90      g_list_free (mux->streamheader);
91      mux->streamheader = NULL;
92    }
93 +  if (mux->alignment_adapter) {
94 +    gst_adapter_clear (mux->alignment_adapter);
95 +    g_object_unref (mux->alignment_adapter);
96 +    mux->alignment_adapter = NULL;
97 +  }
98 +
99 +  if (mux->element_index)
100 +    gst_object_unref (mux->element_index);
101 +
102    GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
103  }
104  
105 @@ -331,12 +369,27 @@
106          walk = g_slist_next (walk);
107        }
108        break;
109 +    case ARG_ALIGNMENT:
110 +      mux->packets_per_buffer = g_value_get_uint (value);
111 +      mux->arbitrary_align = TRUE;
112 +      break;
113      default:
114        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
115        break;
116    }
117  }
118  
119 +guint
120 +get_packets_per_buffer (MpegTsMux * mux)
121 +{
122 +  if (mux->arbitrary_align == TRUE) {
123 +    return mux->packets_per_buffer;
124 +  } else if (mux->m2ts_mode) {
125 +    return BDMV_PACKETS_PER_BUFFER;
126 +  }
127 +  return DEFAULT_PACKETS_PER_BUFFER;
128 +}
129 +
130  static void
131  gst_mpegtsmux_get_property (GObject * object, guint prop_id,
132      GValue * value, GParamSpec * pspec)
133 @@ -356,6 +409,9 @@
134      case ARG_PMT_INTERVAL:
135        g_value_set_uint (value, mux->pmt_interval);
136        break;
137 +    case ARG_ALIGNMENT:
138 +      g_value_set_uint (value, get_packets_per_buffer (mux));
139 +      break;
140      default:
141        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
142        break;
143 @@ -363,6 +419,37 @@
144  }
145  
146  static void
147 +mpegtsmux_set_index (GstElement * element, GstIndex * index)
148 +{
149 +  MpegTsMux *mux = GST_MPEG_TSMUX (element);
150 +
151 +  GST_OBJECT_LOCK (mux);
152 +  if (mux->element_index)
153 +    gst_object_unref (mux->element_index);
154 +  mux->element_index = index ? gst_object_ref (index) : NULL;
155 +  GST_OBJECT_UNLOCK (mux);
156 +  GST_DEBUG_OBJECT (mux, "Set index %" GST_PTR_FORMAT, mux->element_index);
157 +  gst_index_add_format (index, mux->element_index_writer_id, pts_format);
158 +  gst_index_add_format (index, mux->element_index_writer_id, spn_format);
159 +}
160 +
161 +static GstIndex *
162 +mpegtsmux_get_index (GstElement * element)
163 +{
164 +  GstIndex *result = NULL;
165 +  MpegTsMux *mux = GST_MPEG_TSMUX (element);
166 +
167 +  GST_OBJECT_LOCK (mux);
168 +  if (mux->element_index)
169 +    result = gst_object_ref (mux->element_index);
170 +  GST_OBJECT_UNLOCK (mux);
171 +
172 +  GST_DEBUG_OBJECT (mux, "Returning index %" GST_PTR_FORMAT, result);
173 +
174 +  return result;
175 +}
176 +
177 +static void
178  release_buffer_cb (guint8 * data, void *user_data)
179  {
180    GstBuffer *buf = (GstBuffer *) user_data;
181 @@ -505,6 +592,24 @@
182      ret = GST_FLOW_OK;
183    }
184  
185 +  if (mux->element_index) {
186 +    gboolean parsed = FALSE;
187 +    if (ts_data->stream->is_video_stream) {
188 +      if (gst_structure_get_boolean (s, "parsed", &parsed) && parsed) {
189 +        if (mux->element_index_writer_id == -1) {
190 +          gst_index_get_writer_id (mux->element_index, GST_OBJECT (mux),
191 +              &mux->element_index_writer_id);
192 +          GST_INFO_OBJECT (mux,
193 +              "created GstIndex writer_id = %d for PID 0x%04x",
194 +              mux->element_index_writer_id, ts_data->pid);
195 +        }
196 +      } else
197 +        GST_WARNING_OBJECT (pad,
198 +            "Indexing capability for PID=0x%04x disabled - parsed input stream is required!",
199 +            ts_data->pid);
200 +    }
201 +  }
202 +
203  beach:
204    gst_caps_unref (caps);
205    return ret;
206 @@ -659,6 +764,105 @@
207    return best;
208  }
209  
210 +static GstFlowReturn
211 +aligned_push (MpegTsMux * mux, GstBuffer * buf)
212 +{
213 +  guint accu_bytes, packet_length;
214 +  GstBuffer *out_buf;
215 +
216 +  if (get_packets_per_buffer (mux) == 0) {
217 +    return gst_pad_push (mux->srcpad, buf);
218 +  }
219 +
220 +  packet_length = mux->m2ts_mode ? M2TS_PACKET_LENGTH : NORMAL_TS_PACKET_LENGTH;
221 +  gst_adapter_push (mux->alignment_adapter, buf);
222 +
223 +  accu_bytes = gst_adapter_available (mux->alignment_adapter);
224 +  GST_DEBUG_OBJECT (mux,
225 +      "Accumulating packet in alignment adapter, accu_bytes=%i", accu_bytes);
226 +
227 +  if (accu_bytes == get_packets_per_buffer (mux) * packet_length) {
228 +    out_buf = gst_adapter_take_buffer (mux->alignment_adapter, accu_bytes);
229 +    gst_buffer_set_caps (out_buf, GST_PAD_CAPS (mux->srcpad));
230 +    gst_adapter_clear (mux->alignment_adapter);
231 +    GST_DEBUG_OBJECT (mux,
232 +        "Accumulated desired amount of packets in alignment unit, handing off %i bytes",
233 +        accu_bytes);
234 +    return gst_pad_push (mux->srcpad, out_buf);
235 +  } else if (accu_bytes > get_packets_per_buffer (mux) * packet_length) {
236 +    GST_WARNING_OBJECT (mux, "Packet alignment error!");
237 +    gst_adapter_clear (mux->alignment_adapter);
238 +    return GST_FLOW_CUSTOM_ERROR;
239 +  }
240 +
241 +  return GST_FLOW_OK;
242 +}
243 +
244 +static void
245 +mpegtsmux_eos_align (MpegTsMux * mux)
246 +{
247 +  guint accu_bytes, packet_length, packets_needed, dummy_packet_count;
248 +  guint continuity_counter;
249 +  unsigned char header[4];
250 +  guint p;
251 +  GstBuffer *buf;
252 +  guint32 m2ts_header = 0;
253 +
254 +  accu_bytes = gst_adapter_available (mux->alignment_adapter);
255 +  packet_length = mux->m2ts_mode ? M2TS_PACKET_LENGTH : NORMAL_TS_PACKET_LENGTH;
256 +  packets_needed = get_packets_per_buffer (mux) - accu_bytes / packet_length;
257 +
258 +  if (get_packets_per_buffer (mux) == 0 || accu_bytes == 0) {
259 +    return;
260 +  }
261 +
262 +  GST_DEBUG_OBJECT (mux,
263 +      "received EOS - %i bytes accumulated in alignment adapter -> %i dummy packets needed for padding!\n",
264 +      accu_bytes, packets_needed);
265 +
266 +  if (mux->m2ts_mode) {
267 +    gst_adapter_copy (mux->alignment_adapter, header,
268 +        accu_bytes - packet_length, 4);
269 +    m2ts_header = GST_READ_UINT32_BE (header);
270 +    gst_adapter_copy (mux->alignment_adapter, header,
271 +        accu_bytes - packet_length + 7, 1);
272 +  } else {
273 +    gst_adapter_copy (mux->alignment_adapter, header,
274 +        accu_bytes - packet_length + 3, 1);
275 +  }
276 +
277 +  continuity_counter = header[0] & 0xF;
278 +
279 +  for (dummy_packet_count = 0; dummy_packet_count < packets_needed;
280 +      dummy_packet_count++) {
281 +    buf = gst_buffer_new_and_alloc (packet_length);
282 +    if (mux->m2ts_mode) {
283 +      // monotonically increase m2ts_header
284 +      m2ts_header++;
285 +      GST_WRITE_UINT32_BE (GST_BUFFER_DATA (buf), m2ts_header);
286 +      p = (guint) GST_BUFFER_DATA (buf) + 4;
287 +    } else {
288 +      p = (guint) GST_BUFFER_DATA (buf);
289 +    }
290 +    GST_WRITE_UINT8 (p++, TSMUX_SYNC_BYTE);
291 +    // dummy PID
292 +    GST_WRITE_UINT16_BE (p, 0x1FFF);
293 +    p += 2;
294 +    // adaptation field exists | no payload exists | continuity counter
295 +    GST_WRITE_UINT8 (p++, 0x20 + ((++continuity_counter) & 0xF));
296 +    // adaptation field length | flags
297 +    GST_WRITE_UINT16_BE (p, 0xB700);
298 +    p += 2;
299 +    // adaptation field
300 +    memset ((guint*)p, 0xFF, 0xB6);
301 +
302 +    aligned_push (mux, buf);
303 +    GST_LOG_OBJECT (mux,
304 +        "generated dummy packet %i with m2ts_header=0x%x, contiuity=0x%02x\n",
305 +        dummy_packet_count, m2ts_header, continuity_counter);
306 +  }
307 +}
308 +
309  #define COLLECT_DATA_PAD(collect_data) (((GstCollectData *)(collect_data))->pad)
310  
311  static MpegTsPadData *
312 @@ -971,6 +1175,7 @@
313    } else {
314      /* FIXME: Drain all remaining streams */
315      /* At EOS */
316 +    mpegtsmux_eos_align (mux);
317      gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
318    }
319  
320 @@ -1081,7 +1286,7 @@
321      GST_LOG_OBJECT (mux, "marking as delta unit");
322      GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
323    } else {
324 -    GST_DEBUG_OBJECT (mux, "marking as non-delta unit");
325 +    GST_DEBUG_OBJECT (mux, "marking as non-delta unit, spn %i", mux->spn_count);
326      mux->is_delta = TRUE;
327    }
328  }
329 @@ -1104,6 +1309,8 @@
330      return FALSE;
331    }
332  
333 +//   mux->spn_count++;
334 +
335    /* copies the TS data of 188 bytes to the m2ts buffer at an offset
336       of 4 bytes to leave space for writing the timestamp later */
337    memcpy (GST_BUFFER_DATA (buf) + 4, data, len);
338 @@ -1168,13 +1375,25 @@
339          break;
340        gst_buffer_set_caps (out_buf, GST_PAD_CAPS (mux->srcpad));
341        GST_BUFFER_TIMESTAMP (out_buf) = MPEG_SYS_TIME_TO_GSTTIME (cur_pcr);
342 +      
343 +      mux->spn_count++;
344 +
345 +      if (mux->element_index) {
346 +        if (!GST_BUFFER_FLAG_IS_SET (out_buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
347 +          gst_index_add_association (mux->element_index,
348 +              mux->element_index_writer_id,
349 +              GST_ASSOCIATION_FLAG_KEY_UNIT, spn_format,
350 +              mux->spn_count, pts_format,
351 +              GSTTIME_TO_MPEGTIME (GST_BUFFER_TIMESTAMP (out_buf)), NULL);
352 +        }
353 +      }
354  
355        /* Write the 4 byte timestamp value, bottom 30 bits only = PCR */
356        GST_WRITE_UINT32_BE (GST_BUFFER_DATA (out_buf), cur_pcr & 0x3FFFFFFF);
357  
358        GST_LOG_OBJECT (mux, "Outputting a packet of length %d PCR %"
359            G_GUINT64_FORMAT, M2TS_PACKET_LENGTH, cur_pcr);
360 -      ret = gst_pad_push (mux->srcpad, out_buf);
361 +      ret = aligned_push (mux, out_buf);
362        if (G_UNLIKELY (ret != GST_FLOW_OK)) {
363          mux->last_flow_ret = ret;
364          return FALSE;
365 @@ -1190,7 +1409,7 @@
366  
367    GST_LOG_OBJECT (mux, "Outputting a packet of length %d PCR %"
368        G_GUINT64_FORMAT, M2TS_PACKET_LENGTH, new_pcr);
369 -  ret = gst_pad_push (mux->srcpad, buf);
370 +  ret = aligned_push (mux, buf);
371    if (G_UNLIKELY (ret != GST_FLOW_OK)) {
372      mux->last_flow_ret = ret;
373      return FALSE;
374 @@ -1221,7 +1440,7 @@
375  
376    GST_BUFFER_TIMESTAMP (buf) = mux->last_ts;
377  
378 -  ret = gst_pad_push (mux->srcpad, buf);
379 +  ret = aligned_push (mux, buf);
380    if (G_UNLIKELY (ret != GST_FLOW_OK)) {
381      mux->last_flow_ret = ret;
382      return FALSE;
383 @@ -1319,6 +1538,8 @@
384      case GST_STATE_CHANGE_READY_TO_NULL:
385        if (mux->adapter)
386          gst_adapter_clear (mux->adapter);
387 +      if (mux->alignment_adapter)
388 +        gst_adapter_clear (mux->alignment_adapter);
389        break;
390      default:
391        break;
392 diff --git a/gst/mpegtsmux/mpegtsmux.h b/gst/mpegtsmux/mpegtsmux.h
393 index 26003a8..1b88a33 100644
394 --- a/gst/mpegtsmux/mpegtsmux.h
395 +++ b/gst/mpegtsmux/mpegtsmux.h
396 @@ -130,6 +130,14 @@
397    gboolean streamheader_sent;
398    GstClockTime pending_key_unit_ts;
399    GstEvent *force_key_unit_event;
400 +
401 +  guint32 spn_count;
402 +  GstIndex *element_index;
403 +  gint      element_index_writer_id;
404
405 +  gboolean arbitrary_align;
406 +  guint packets_per_buffer;
407 +  GstAdapter *alignment_adapter;
408  };
409  
410  struct MpegTsMuxClass  {
411 @@ -186,6 +194,9 @@
412  #define MAX_PROG_NUMBER        32
413  #define DEFAULT_PROG_ID        0
414  
415 +#define DEFAULT_PACKETS_PER_BUFFER 0
416 +#define BDMV_PACKETS_PER_BUFFER           32
417 +
418  G_END_DECLS
419  
420  #endif
421 -- 
422 1.7.5.4
423