From 2e17e675f9aa75ce0d52df6d42b78eb407662009 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Mon, 14 Mar 2011 17:35:30 +0100 Subject: [PATCH] core: encodebin-based MPEG TS transcoder Video and audio encoders and muxer are correctly auto-selected by encodebin for us, however we don't set the bitrate currently as we don't have a reliable way to do so. Co-author: Zeeshan Ali (Khattak) --- po/POTFILES.in | 1 - po/POTFILES.skip | 1 - src/rygel/Makefile.am | 1 - src/rygel/rygel-mp2ts-transcoder-bin.vala | 108 ----------------------- src/rygel/rygel-mp2ts-transcoder.vala | 141 +++++++++++++++++------------- 5 files changed, 81 insertions(+), 171 deletions(-) delete mode 100644 src/rygel/rygel-mp2ts-transcoder-bin.vala diff --git a/po/POTFILES.in b/po/POTFILES.in index d7fec05..75ee862 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -114,7 +114,6 @@ src/rygel/rygel-visual-item.vala src/rygel/rygel-media-object.vala src/rygel/rygel-media-receiver-registrar.vala src/rygel/rygel-meta-config.vala -src/rygel/rygel-mp2ts-transcoder-bin.vala src/rygel/rygel-mp2ts-transcoder.vala src/rygel/rygel-mp3-transcoder-bin.vala src/rygel/rygel-mp3-transcoder.vala diff --git a/po/POTFILES.skip b/po/POTFILES.skip index 1cac003..b781977 100644 --- a/po/POTFILES.skip +++ b/po/POTFILES.skip @@ -72,7 +72,6 @@ src/rygel/rygel-video-item.c src/rygel/rygel-visual-item.c src/rygel/rygel-meta-config.c src/rygel/rygel-metadata-extractor.c -src/rygel/rygel-mp2ts-transcoder-bin.c src/rygel/rygel-mp3-transcoder-bin.c src/rygel/rygel-plugin-loader.c src/rygel/rygel-root-device-factory.c diff --git a/src/rygel/Makefile.am b/src/rygel/Makefile.am index ef7ad08..c0fb6b7 100644 --- a/src/rygel/Makefile.am +++ b/src/rygel/Makefile.am @@ -95,7 +95,6 @@ VAPI_SOURCE_FILES = \ rygel-mp2ts-transcoder.vala \ rygel-mp3-transcoder.vala \ rygel-l16-transcoder.vala \ - rygel-mp2ts-transcoder-bin.vala \ rygel-mp3-transcoder-bin.vala \ rygel-l16-transcoder-bin.vala \ rygel-wma-transcoder.vala \ diff --git a/src/rygel/rygel-mp2ts-transcoder-bin.vala b/src/rygel/rygel-mp2ts-transcoder-bin.vala deleted file mode 100644 index b4c4f3a..0000000 --- a/src/rygel/rygel-mp2ts-transcoder-bin.vala +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2009 Nokia Corporation. - * - * Author: Zeeshan Ali (Khattak) - * - * - * 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); - } - } -} diff --git a/src/rygel/rygel-mp2ts-transcoder.vala b/src/rygel/rygel-mp2ts-transcoder.vala index 79f4eaa..f077a48 100644 --- a/src/rygel/rygel-mp2ts-transcoder.vala +++ b/src/rygel/rygel-mp2ts-transcoder.vala @@ -31,10 +31,10 @@ internal enum Rygel.MP2TSProfile { /** * 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}; @@ -43,10 +43,8 @@ internal class Rygel.MP2TSTranscoder : Rygel.Transcoder { 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; @@ -59,7 +57,25 @@ internal class Rygel.MP2TSTranscoder : Rygel.Transcoder { 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, @@ -72,7 +88,7 @@ internal class Rygel.MP2TSTranscoder : Rygel.Transcoder { 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; } @@ -100,67 +116,72 @@ internal class Rygel.MP2TSTranscoder : Rygel.Transcoder { 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); } } -- 2.7.4