+++ /dev/null
-/*
- * Copyright (C) 2009 Nokia Corporation.
- *
- * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
- * <zeeshan.ali@nokia.com>
- *
- * This file is part of Rygel.
- *
- * Rygel is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * Rygel 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-using Gst;
-
-/**
- * A Gst.Bin derivative that implements transcoding of any type of media (using
- * decodebin2) to mpeg transport stream containing mpeg 2 video and mp2 audio.
- */
-internal class Rygel.MP2TSTranscoderBin : Gst.Bin {
- private const string DECODEBIN = "decodebin2";
- private const string MUXER = "mpegtsmux";
-
- private const string AUDIO_ENC_SINK = "audio-enc-sink-pad";
- private const string VIDEO_ENC_SINK = "sink";
-
- private dynamic Element audio_enc;
- private dynamic Element video_enc;
- private dynamic Element muxer;
-
- public MP2TSTranscoderBin (MediaItem item,
- Element src,
- MP2TSTranscoder transcoder)
- throws Error {
- dynamic Element decodebin = GstUtils.create_element (DECODEBIN,
- DECODEBIN);
- var mp3_transcoder = new MP3Transcoder (MP3Layer.TWO);
- this.audio_enc = mp3_transcoder.create_encoder (item,
- null,
- AUDIO_ENC_SINK);
- this.video_enc = transcoder.create_encoder (item, null, VIDEO_ENC_SINK);
- this.muxer = GstUtils.create_element (MUXER, MUXER);
-
- this.add_many (src,
- decodebin,
- this.audio_enc,
- this.video_enc,
- this.muxer);
- src.link (decodebin);
-
- var src_pad = muxer.get_static_pad ("src");
- var ghost = new GhostPad (null, src_pad);
- this.add_pad (ghost);
-
- decodebin.pad_added.connect (this.decodebin_pad_added);
- decodebin.autoplug_continue.connect (this.autoplug_continue);
- }
-
- private bool autoplug_continue (Element decodebin,
- Pad new_pad,
- Caps caps) {
- var muxer_pad = this.muxer.get_compatible_pad (new_pad, null);
-
- if (muxer_pad == null) {
- return true;
- } else {
- return new_pad.link (muxer_pad) != PadLinkReturn.OK;
- }
- }
-
- private void decodebin_pad_added (Element decodebin, Pad new_pad) {
- Element encoder;
- Pad enc_pad;
-
- var audio_enc_pad = this.audio_enc.get_pad (AUDIO_ENC_SINK);
- var video_enc_pad = this.video_enc.get_pad (VIDEO_ENC_SINK);
-
- // Check which encoder to use
- if (new_pad.can_link (audio_enc_pad)) {
- encoder = this.audio_enc;
- enc_pad = audio_enc_pad;
- } else if (new_pad.can_link (video_enc_pad)) {
- encoder = this.video_enc;
- enc_pad = video_enc_pad;
- } else {
- return;
- }
-
- encoder.link (this.muxer);
-
- if (new_pad.link (enc_pad) != PadLinkReturn.OK) {
- var error = new GstError.LINK (_("Failed to link pad %s to %s"),
- new_pad.name,
- enc_pad.name);
- GstUtils.post_error (this, error);
- }
- }
-}
/**
* Transcoder for mpeg transport stream containing mpeg 2 video and mp2 audio.
- * This element uses MP2TSTrancoderBin for actual transcoding.
*/
internal class Rygel.MP2TSTranscoder : Rygel.Transcoder {
private const int VIDEO_BITRATE = 3000;
+ private const int AUDIO_BITRATE = 256;
// HD
private const int[] WIDTH = {720, 1280};
private const string[] PROFILES = {"MPEG_TS_SD_EU_ISO", "MPEG_TS_HD_NA_ISO"};
private const int BITRATE = 3000000;
- private const string VIDEO_ENCODER = "ffenc_mpeg2video";
- private const string COLORSPACE_CONVERT = "ffmpegcolorspace";
- private const string VIDEO_RATE = "videorate";
- private const string VIDEO_SCALE = "videoscale";
+ private const string DECODE_BIN = "decodebin2";
+ private const string ENCODE_BIN = "encodebin";
private MP2TSProfile profile;
public override Element create_source (MediaItem item,
Element src)
throws Error {
- return new MP2TSTranscoderBin (item, src, this);
+ dynamic Element decoder = GstUtils.create_element (DECODE_BIN,
+ DECODE_BIN);
+ dynamic Element encoder = GstUtils.create_element (ENCODE_BIN,
+ ENCODE_BIN);
+
+ encoder.profile = this.get_encoding_profile ();
+
+ var bin = new Bin ("mp2-ts-transcoder-bin");
+ bin.add_many (src, decoder, encoder);
+
+ src.link (decoder);
+
+ decoder.pad_added.connect (this.on_decoder_pad_added);
+
+ var pad = encoder.get_static_pad ("src");
+ var ghost = new GhostPad (null, pad);
+ bin.add_pad (ghost);
+
+ return bin;
}
public override DIDLLiteResource? add_resource (DIDLLiteItem didl_item,
resource.width = WIDTH[profile];
resource.height = HEIGHT[profile];
- resource.bitrate = (VIDEO_BITRATE + MP3Transcoder.BITRATE) * 1000 / 8;
+ resource.bitrate = (VIDEO_BITRATE + AUDIO_BITRATE) * 1000 / 8;
return resource;
}
return distance;
}
- public Element create_encoder (MediaItem item,
- string? src_pad_name,
- string? sink_pad_name)
- throws Error {
- var videorate = GstUtils.create_element (VIDEO_RATE, VIDEO_RATE);
- var videoscale = GstUtils.create_element (VIDEO_SCALE, VIDEO_SCALE);
- var convert = GstUtils.create_element (COLORSPACE_CONVERT,
- COLORSPACE_CONVERT);
- dynamic Element encoder = GstUtils.create_element (VIDEO_ENCODER,
- VIDEO_ENCODER);
+ private void on_decoder_pad_added (Element decodebin, Pad new_pad) {
+ var bin = decodebin.get_parent () as Bin;
+ assert (bin != null);
- encoder.bitrate = (int) VIDEO_BITRATE * 1000;
+ var encoder = bin.get_by_name (ENCODE_BIN);
+ assert (encoder != null);
- var bin = new Bin ("video-encoder-bin");
- bin.add_many (videorate, videoscale, convert, encoder);
+ var encoder_pad = encoder.get_compatible_pad (new_pad, null);
+ if (encoder_pad == null) {
+ debug ("No compatible encodebin pad found for pad '%s', ignoring..",
+ new_pad.name);
+ return;
+ } else {
+ debug ("pad '%s' with caps '%s' is compatible with '%s'",
+ new_pad.name,
+ new_pad.get_caps ().to_string (),
+ encoder_pad.name);
+ }
- convert.link_many (videoscale, videorate);
+ if (new_pad.link (encoder_pad) != PadLinkReturn.OK) {
+ var error = new GstError.LINK (_("Failed to link pad %s to %s"),
+ new_pad.name,
+ encoder_pad.name);
+ GstUtils.post_error (bin, error);
+ }
+ }
- int pixel_w;
- int pixel_h;
+ private EncodingContainerProfile get_encoding_profile () {
+ var container_format = Caps.from_string ("video/mpegts," +
+ "systemstream=true," +
+ "packetsize=188");
- var video_item = item as VideoItem;
+ var enc_container_profile = new EncodingContainerProfile
+ ("mpeg-ts-profile",
+ null,
+ container_format,
+ null);
- if (video_item.pixel_width > 0 && video_item.pixel_height > 0) {
- pixel_w = video_item.width *
- HEIGHT[this.profile] *
- video_item.pixel_width;
- pixel_h = video_item.height *
- WIDTH[this.profile] *
- video_item.pixel_height;
- } else {
- // Original pixel-ratio not provided, lets just use 1:1
- pixel_w = 1;
- pixel_h = 1;
- }
+ enc_container_profile.add_profile (this.get_video_profile ());
+ enc_container_profile.add_profile (this.get_audio_profile ());
- var caps = new Caps.simple ("video/x-raw-yuv",
- "width",
- typeof (int),
- WIDTH[this.profile],
- "height",
- typeof (int),
- HEIGHT[this.profile],
- "framerate",
- typeof (Fraction),
- FRAME_RATE[this.profile],
- 1,
- "pixel-aspect-ratio",
- typeof (Fraction),
- pixel_w,
- pixel_h);
- videorate.link_filtered (encoder, caps);
-
- var pad = convert.get_static_pad ("sink");
- var ghost = new GhostPad (sink_pad_name, pad);
- bin.add_pad (ghost);
+ return enc_container_profile;
+ }
- pad = encoder.get_static_pad ("src");
- ghost = new GhostPad (src_pad_name, pad);
- bin.add_pad (ghost);
+ private EncodingVideoProfile get_video_profile () {
+ var format = Caps.from_string ("video/mpeg," +
+ "mpegversion=2," +
+ "systemstream=false," +
+ "framerate=(fraction)25/1");
+ var restriction = Caps.from_string
+ ("video/x-raw-yuv,width=" +
+ WIDTH[this.profile].to_string () +
+ ",height=" +
+ HEIGHT[this.profile].to_string () +
+ ",framerate=(fraction)" +
+ FRAME_RATE[this.profile].to_string () +
+ "/1");
+
+ // FIXME: We should use the preset to set bitrate
+ return new EncodingVideoProfile (format, null, restriction, 1);
+ }
- return bin;
+ private EncodingAudioProfile get_audio_profile () {
+ var format = Caps.from_string ("audio/mpeg,mpegversion=4");
+
+ // FIXME: We should use the preset to set bitrate
+ return new EncodingAudioProfile (format, null, null, 1);
}
}