/* GStreamer mpeg2enc (mjpegtools) wrapper * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net> * (c) 2006 Mark Nauwelaerts <manauw@skynet.be> * * gstmpeg2encstreamwriter.cc: GStreamer/mpeg2enc output wrapper * * 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "gstmpeg2enc.hh" #include "gstmpeg2encstreamwriter.hh" #include <string.h> #if GST_MJPEGTOOLS_API >= 10800 /* * Class init stuff. */ GstMpeg2EncStreamWriter::GstMpeg2EncStreamWriter (GstPad * in_pad, EncoderParams * params) { pad = in_pad; gst_object_ref (pad); buf = NULL; } GstMpeg2EncStreamWriter::~GstMpeg2EncStreamWriter () { gst_object_unref (pad); } void GstMpeg2EncStreamWriter::WriteOutBufferUpto (const guint8 * buffer, const guint32 flush_upto) { GstBuffer *buf, *inbuf; GstMpeg2enc *enc = GST_MPEG2ENC (GST_PAD_PARENT (pad)); buf = gst_buffer_new_and_alloc (flush_upto); memcpy (GST_BUFFER_DATA (buf), buffer, flush_upto); flushed += flush_upto; /* this should not block anything else (e.g. chain), but if it does, * it's ok as mpeg2enc is not really a loop-based element, but push-based */ GST_MPEG2ENC_MUTEX_LOCK (enc); /* best effort at giving output some meaningful time metadata * no mpeg2enc specs on this though, but it might help getting the output * into container formats that really do like timestamps (unlike mplex) */ if ((inbuf = (GstBuffer *) g_queue_pop_head (enc->time))) { GST_BUFFER_TIMESTAMP (buf) = GST_BUFFER_TIMESTAMP (inbuf); GST_BUFFER_DURATION (buf) = GST_BUFFER_DURATION (inbuf); gst_buffer_unref (inbuf); } gst_buffer_set_caps (buf, GST_PAD_CAPS (pad)); enc->srcresult = gst_pad_push (pad, buf); GST_MPEG2ENC_MUTEX_UNLOCK (enc); } guint64 GstMpeg2EncStreamWriter::BitCount () { return flushed * 8ll; } #else #define BUFSIZE (128*1024) /* * Class init stuff. */ GstMpeg2EncStreamWriter::GstMpeg2EncStreamWriter (GstPad * in_pad, EncoderParams * params): ElemStrmWriter (*params) { pad = in_pad; gst_object_ref (pad); buf = NULL; } GstMpeg2EncStreamWriter::~GstMpeg2EncStreamWriter () { gst_object_unref (pad); } /* * Output functions. */ void GstMpeg2EncStreamWriter::PutBits (guint32 val, gint n) { /* only relevant bits. Note that (according to Andrew), * some CPUs do bitshifts modulo wordsize (32), which * means that we have to check for n != 32 before * bitshifting to the relevant bits (i.e. 0xffffffff << * 32 == 0xffffffff). */ if (n != 32) val &= ~(0xffffffffU << n); /* write data */ while (n >= outcnt) { if (!buf) { buf = gst_buffer_new_and_alloc (BUFSIZE); GST_BUFFER_SIZE (buf) = 0; } outbfr = (outbfr << outcnt) | (val >> (n - outcnt)); GST_BUFFER_DATA (buf)[GST_BUFFER_SIZE (buf)++] = outbfr; n -= outcnt; outcnt = 8; bytecnt++; if (GST_BUFFER_SIZE (buf) >= BUFSIZE) FrameFlush (); } /* cache remaining bits */ if (n != 0) { outbfr = (outbfr << n) | val; outcnt -= n; } } void GstMpeg2EncStreamWriter::FrameBegin () { } void GstMpeg2EncStreamWriter::FrameFlush () { GstMpeg2enc *enc = GST_MPEG2ENC (GST_PAD_PARENT (pad)); if (buf) { /* this should not block anything else (e.g. chain), but if it does, * it's ok as mpeg2enc is not really a loop-based element, but push-based */ GST_MPEG2ENC_MUTEX_LOCK (enc); gst_buffer_set_caps (buf, GST_PAD_CAPS (pad)); enc->srcresult = gst_pad_push (pad, buf); GST_MPEG2ENC_MUTEX_UNLOCK (enc); buf = NULL; } } void GstMpeg2EncStreamWriter::FrameDiscard () { } #endif /* GST_MJPEGTOOLS_API >= 10800 */