From d01583ed289bf45f25e1f6962be864055e849a88 Mon Sep 17 00:00:00 2001 From: TangoCash Date: Sat, 3 Jan 2015 19:24:37 +0100 Subject: [PATCH] implement simple gstreamer_plackback Origin commit data ------------------ Branch: master Commit: https://github.com/neutrino-images/ni-libstb-hal/commit/410b707f769dad76356242d8355503738148687a Author: TangoCash Date: 2015-01-03 (Sat, 03 Jan 2015) ------------------ No further description and justification available within origin commit message! ------------------ This commit was generated by Migit --- configure.ac | 13 + generic-pc/Makefile.am | 12 +- generic-pc/glfb.cpp | 16 +- generic-pc/glfb.h | 2 + generic-pc/playback_gst.cpp | 812 ++++++++++++++++++++++++++++++++++++ generic-pc/playback_gst.h | 88 ++++ 6 files changed, 938 insertions(+), 5 deletions(-) create mode 100644 generic-pc/playback_gst.cpp create mode 100644 generic-pc/playback_gst.h diff --git a/configure.ac b/configure.ac index cd79036..5f25b41 100644 --- a/configure.ac +++ b/configure.ac @@ -23,7 +23,20 @@ if test x"$BOXTYPE" = x"tripledragon"; then TUXBOX_APPS_LIB_PKGCONFIG(DIRECTFB, directfb) fi +AC_ARG_ENABLE(gstreamer, + AS_HELP_STRING(--enable-gstreamer,use gstreamer playback), + ,[enable_gstreamer=no]) + +AM_CONDITIONAL(ENABLE_GSTREAMER,test "$enable_gstreamer" = "yes") +if test "$enable_gstreamer" = "yes"; then + AC_DEFINE(ENABLE_GSTREAMER,1,[enable gstreamer]) +fi + if test x$BOXTYPE = xgeneric -a x$BOXMODEL != xraspi; then +if test x$ENABLE_GSTREAMER = x1; then + PKG_CHECK_MODULES([GSTREAMER], [gstreamer-0.10]) + PKG_CHECK_MODULES([GSTREAMER_INTERFACES], [gstinterfaces-0.10]) +fi PKG_CHECK_MODULES([AVFORMAT], [libavformat >= 53.21.1]) PKG_CHECK_MODULES([AVCODEC], [libavcodec >= 54.28.0]) # don't know which version is exactly needed here... diff --git a/generic-pc/Makefile.am b/generic-pc/Makefile.am index f4dbbc7..67fbc95 100644 --- a/generic-pc/Makefile.am +++ b/generic-pc/Makefile.am @@ -22,7 +22,17 @@ libgeneric_la_SOURCES = \ audio.cpp \ glfb.cpp \ init.cpp \ - playback.cpp \ pwrmngr.cpp \ record.cpp +if ENABLE_GSTREAMER +libgeneric_la_SOURCES += \ + playback_gst.cpp +AM_LDFLAGS += \ + -lgstreamer-0.10 \ + -lgstinterfaces-0.10 +else +libgeneric_la_SOURCES += \ + playback.cpp +endif + diff --git a/generic-pc/glfb.cpp b/generic-pc/glfb.cpp index cf6b77b..fd48705 100644 --- a/generic-pc/glfb.cpp +++ b/generic-pc/glfb.cpp @@ -38,6 +38,7 @@ #include #include #include "glfb.h" +#include #include "video_lib.h" #include "audio_lib.h" @@ -121,10 +122,16 @@ void GLFramebuffer::initKeys() mSpecialMap[GLUT_KEY_F3] = KEY_YELLOW; mSpecialMap[GLUT_KEY_F4] = KEY_BLUE; - mSpecialMap[GLUT_KEY_F5] = KEY_WWW; - mSpecialMap[GLUT_KEY_F6] = KEY_SUBTITLE; - mSpecialMap[GLUT_KEY_F7] = KEY_MOVE; - mSpecialMap[GLUT_KEY_F8] = KEY_SLEEP; + mSpecialMap[GLUT_KEY_F5] = KEY_PLAY; + mSpecialMap[GLUT_KEY_F6] = KEY_STOP; + mSpecialMap[GLUT_KEY_F7] = KEY_FORWARD; + mSpecialMap[GLUT_KEY_F8] = KEY_REWIND; + + mSpecialMap[GLUT_KEY_F9] = KEY_RECORD; + mSpecialMap[GLUT_KEY_F10] = KEY_PAUSE; + + mSpecialMap[GLUT_KEY_F11] = KEY_NEXT; + mSpecialMap[GLUT_KEY_F12] = KEY_PREVIOUS; mSpecialMap[GLUT_KEY_PAGE_UP] = KEY_PAGEUP; mSpecialMap[GLUT_KEY_PAGE_DOWN] = KEY_PAGEDOWN; @@ -205,6 +212,7 @@ void GLFramebuffer::setupCtx() glutInitWindowSize(mX[0], mY[0]); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); glutCreateWindow("Neutrino"); + GLWinID = glXGetCurrentDrawable(); // this was the holy grail to get the right window handle for gstreamer :D } void GLFramebuffer::setupOSDBuffer() diff --git a/generic-pc/glfb.h b/generic-pc/glfb.h index c6999d5..78376ba 100644 --- a/generic-pc/glfb.h +++ b/generic-pc/glfb.h @@ -47,6 +47,7 @@ public: void clear(); fb_var_screeninfo getScreenInfo() { return screeninfo; } + int getWindowID() { return GLWinID; } private: fb_var_screeninfo screeninfo; @@ -61,6 +62,7 @@ private: float zoom; /* for cropping */ float xscale; /* and aspect ratio */ int mCrop; /* DISPLAY_AR_MODE */ + int GLWinID; bool mFullscreen; /* fullscreen? */ bool mReInit; /* setup things for GL */ diff --git a/generic-pc/playback_gst.cpp b/generic-pc/playback_gst.cpp new file mode 100644 index 0000000..0402868 --- /dev/null +++ b/generic-pc/playback_gst.cpp @@ -0,0 +1,812 @@ +/* + * + * 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. + * + */ + +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#include "dmx_lib.h" +#include "audio_lib.h" +#include "video_lib.h" +#include "glfb.h" + +#include "playback_gst.h" + +#include "lt_debug.h" +#define lt_debug(args...) _lt_debug(HAL_DEBUG_PLAYBACK, this, args) +#define lt_info(args...) _lt_info(HAL_DEBUG_PLAYBACK, this, args) +#define lt_debug_c(args...) _lt_debug(HAL_DEBUG_PLAYBACK, NULL, args) +#define lt_info_c(args...) _lt_info(HAL_DEBUG_PLAYBACK, NULL, args) + +static const char * FILENAME = "[playback.cpp]"; + +#include +#include +#include + +typedef enum +{ + GST_PLAY_FLAG_VIDEO = 0x00000001, + GST_PLAY_FLAG_AUDIO = 0x00000002, + GST_PLAY_FLAG_TEXT = 0x00000004, + GST_PLAY_FLAG_VIS = 0x00000008, + GST_PLAY_FLAG_SOFT_VOLUME = 0x00000010, + GST_PLAY_FLAG_NATIVE_AUDIO = 0x00000020, + GST_PLAY_FLAG_NATIVE_VIDEO = 0x00000040, + GST_PLAY_FLAG_DOWNLOAD = 0x00000080, + GST_PLAY_FLAG_BUFFERING = 0x000000100 +} GstPlayFlags; + + +GstElement * m_gst_playbin = NULL; +GstElement * audioSink = NULL; +GstElement * videoSink = NULL; +gchar * uri = NULL; +GstTagList * m_stream_tags = 0; +static int end_eof = 0; + +extern GLFramebuffer *glfb; + +gint match_sinktype(GstElement *element, gpointer type) +{ + return strcmp(g_type_name(G_OBJECT_TYPE(element)), (const char*)type); +} +GstBusSyncReply Gst_bus_call(GstBus * bus, GstMessage *msg, gpointer user_data) +{ + gchar * sourceName; + + // source + GstObject * source; + source = GST_MESSAGE_SRC(msg); + + if (!GST_IS_OBJECT(source)) + return GST_BUS_DROP; + + sourceName = gst_object_get_name(source); + + switch (GST_MESSAGE_TYPE(msg)) + { + case GST_MESSAGE_EOS: + { + g_message("End-of-stream"); + end_eof = 1; + break; + } + + case GST_MESSAGE_ERROR: + { + gchar * debug; + GError *err; + gst_message_parse_error(msg, &err, &debug); + g_free (debug); + lt_info_c( "%s:%s - GST_MESSAGE_ERROR: %s (%i) from %s\n", FILENAME, __FUNCTION__, err->message, err->code, sourceName ); + if ( err->domain == GST_STREAM_ERROR ) + { + if ( err->code == GST_STREAM_ERROR_CODEC_NOT_FOUND ) + { + if ( g_strrstr(sourceName, "videosink") ) + lt_info_c( "%s:%s - GST_MESSAGE_ERROR: videosink\n", FILENAME, __FUNCTION__ ); //FIXME: how shall playback handle this event??? + else if ( g_strrstr(sourceName, "audiosink") ) + lt_info_c( "%s:%s - GST_MESSAGE_ERROR: audioSink\n", FILENAME, __FUNCTION__ ); //FIXME: how shall playback handle this event??? + } + } + g_error_free(err); + + end_eof = 1; // NOTE: just to exit + + break; + } + + case GST_MESSAGE_INFO: + { + gchar *debug; + GError *inf; + + gst_message_parse_info (msg, &inf, &debug); + g_free (debug); + if ( inf->domain == GST_STREAM_ERROR && inf->code == GST_STREAM_ERROR_DECODE ) + { + if ( g_strrstr(sourceName, "videosink") ) + lt_info_c( "%s:%s - GST_MESSAGE_INFO: videosink\n", FILENAME, __FUNCTION__ ); //FIXME: how shall playback handle this event??? + } + g_error_free(inf); + break; + } + + case GST_MESSAGE_TAG: + { + GstTagList *tags, *result; + gst_message_parse_tag(msg, &tags); + + result = gst_tag_list_merge(m_stream_tags, tags, GST_TAG_MERGE_REPLACE); + if (result) + { + if (m_stream_tags) + gst_tag_list_free(m_stream_tags); + m_stream_tags = result; + } + + const GValue *gv_image = gst_tag_list_get_value_index(tags, GST_TAG_IMAGE, 0); + if ( gv_image ) + { + GstBuffer *buf_image; + buf_image = gst_value_get_buffer (gv_image); + int fd = open("/tmp/.id3coverart", O_CREAT|O_WRONLY|O_TRUNC, 0644); + if(fd >= 0) + { + int ret = write(fd, GST_BUFFER_DATA(buf_image), GST_BUFFER_SIZE(buf_image)); + close(fd); + lt_info_c( "%s:%s - GST_MESSAGE_INFO: cPlayback::state /tmp/.id3coverart %d bytes written\n", FILENAME, __FUNCTION__ , ret); + } + //FIXME: how shall playback handle this event??? + } + gst_tag_list_free(tags); + lt_info_c( "%s:%s - GST_MESSAGE_INFO: update info tags\n", FILENAME, __FUNCTION__); //FIXME: how shall playback handle this event??? + break; + } + + case GST_MESSAGE_STATE_CHANGED: + { + if(GST_MESSAGE_SRC(msg) != GST_OBJECT(m_gst_playbin)) + break; + + GstState old_state, new_state; + gst_message_parse_state_changed(msg, &old_state, &new_state, NULL); + + if(old_state == new_state) + break; + lt_info_c( "%s:%s - GST_MESSAGE_STATE_CHANGED: state transition %s -> %s\n", FILENAME, __FUNCTION__, gst_element_state_get_name(old_state), gst_element_state_get_name(new_state)); + + GstStateChange transition = (GstStateChange)GST_STATE_TRANSITION(old_state, new_state); + + switch(transition) + { + case GST_STATE_CHANGE_NULL_TO_READY: + { + } break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + { + GstIterator *children; + if (audioSink) + { + gst_object_unref(GST_OBJECT(audioSink)); + audioSink = NULL; + } + + if (videoSink) + { + gst_object_unref(GST_OBJECT(videoSink)); + videoSink = NULL; + } + children = gst_bin_iterate_recurse(GST_BIN(m_gst_playbin)); + audioSink = GST_ELEMENT_CAST(gst_iterator_find_custom(children, (GCompareFunc)match_sinktype, (gpointer)"GstDVBAudioSink")); + videoSink = GST_ELEMENT_CAST(gst_iterator_find_custom(children, (GCompareFunc)match_sinktype, (gpointer)"GstDVBVideoSink")); + gst_iterator_free(children); + + } break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + { + } break; + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + { + } break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + { + if (audioSink) + { + gst_object_unref(GST_OBJECT(audioSink)); + audioSink = NULL; + } + if (videoSink) + { + gst_object_unref(GST_OBJECT(videoSink)); + videoSink = NULL; + } + } break; + case GST_STATE_CHANGE_READY_TO_NULL: + { + } break; + } + break; + } +#if 0 + case GST_MESSAGE_ELEMENT: + { + if(gst_structure_has_name(gst_message_get_structure(msg), "prepare-xwindow-id")) + { + // set window id + gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(GST_MESSAGE_SRC (msg)), glfb->getWindowID()); + + // reshape window + gst_x_overlay_set_render_rectangle(GST_X_OVERLAY(GST_MESSAGE_SRC (msg)), 0, 0, glfb->getOSDWidth(), glfb->getOSDHeight()); + + // sync frames + gst_x_overlay_expose(GST_X_OVERLAY(GST_MESSAGE_SRC (msg))); + } + } +#endif + break; + default: + break; + } + + return GST_BUS_DROP; +} + + +cPlayback::cPlayback(int num) +{ + lt_info( "%s:%s\n", FILENAME, __FUNCTION__); + const gchar *nano_str; + guint major, minor, micro, nano; + + gst_init(NULL, NULL); + + gst_version (&major, &minor, µ, &nano); + + if (nano == 1) + nano_str = "(CVS)"; + else if (nano == 2) + nano_str = "(Prerelease)"; + else + nano_str = ""; + + lt_info( "%s:%s - This program is linked against GStreamer %d.%d.%d %s\n", + FILENAME, __FUNCTION__, + major, minor, micro, nano_str); + + mAudioStream = 0; + mSpeed = 0; + + playing = false; + playstate = STATE_STOP; +} + +cPlayback::~cPlayback() +{ + lt_info( "%s:%s\n", FILENAME, __FUNCTION__); + //FIXME: all deleting stuff is done in Close() +} + +//Used by Fileplay +bool cPlayback::Open(playmode_t PlayMode) +{ + lt_info("%s: PlayMode %d\n", __func__, PlayMode); + return true; +} + +// used by movieplay +void cPlayback::Close(void) +{ + lt_info( "%s:%s\n", FILENAME, __FUNCTION__); + + Stop(); + + // disconnect bus handler + if (m_gst_playbin) + { + // disconnect sync handler callback + GstBus * bus = gst_pipeline_get_bus(GST_PIPELINE (m_gst_playbin)); + gst_bus_set_sync_handler(bus, NULL, NULL); + gst_object_unref(bus); + lt_info( "%s:%s - GST bus handler closed\n", FILENAME, __FUNCTION__); + } + + if (m_stream_tags) + gst_tag_list_free(m_stream_tags); + + // close gst + if (m_gst_playbin) + { + if (audioSink) + { + gst_object_unref(GST_OBJECT(audioSink)); + audioSink = NULL; + + lt_info( "%s:%s - GST audio Sink closed\n", FILENAME, __FUNCTION__); + } + + if (videoSink) + { + gst_object_unref(GST_OBJECT(videoSink)); + videoSink = NULL; + + lt_info( "%s:%s - GST video Sink closed\n", FILENAME, __FUNCTION__); + } + + // unref m_gst_playbin + gst_object_unref (GST_OBJECT (m_gst_playbin)); + lt_info( "%s:%s - GST playbin closed\n", FILENAME, __FUNCTION__); + + m_gst_playbin = NULL; + } +} + +// start +bool cPlayback::Start(char *filename, int /*vpid*/, int /*vtype*/, int /*apid*/, int /*ac3*/, int /*duration*/) +{ + lt_info( "%s:%s\n", FILENAME, __FUNCTION__); + + mAudioStream = 0; + + //create playback path + char file[400] = {""}; + bool isHTTP = false; + + if(!strncmp("http://", filename, 7)) + { + isHTTP = true; + } + else if(!strncmp("file://", filename, 7)) + { + isHTTP = false; + } + else if(!strncmp("upnp://", filename, 7)) + { + isHTTP = true; + } + else if(!strncmp("rtmp://", filename, 7)) + { + isHTTP = true; + } + else if(!strncmp("rtsp://", filename, 7)) + { + isHTTP = true; + } + else if(!strncmp("mms://", filename, 6)) + { + isHTTP = true; + } + else + strcat(file, "file://"); + + strcat(file, filename); + + if (isHTTP) + uri = g_uri_escape_string(filename, G_URI_RESERVED_CHARS_GENERIC_DELIMITERS, true); + else + uri = g_filename_to_uri(filename, NULL, NULL); + + lt_info("%s:%s - filename=%s\n", FILENAME, __FUNCTION__, filename); + + // create gst pipeline + m_gst_playbin = gst_element_factory_make("playbin2", "playbin"); + + if(m_gst_playbin) + { + lt_info("%s:%s - m_gst_playbin\n", FILENAME, __FUNCTION__); + + guint flags; + g_object_get(G_OBJECT (m_gst_playbin), "flags", &flags, NULL); + /* avoid video conversion, let the (hardware) sinks handle that */ + flags |= GST_PLAY_FLAG_NATIVE_VIDEO; + /* volume control is done by hardware */ + flags &= ~GST_PLAY_FLAG_SOFT_VOLUME; + + g_object_set(G_OBJECT (m_gst_playbin), "uri", uri, NULL); + g_object_set(G_OBJECT (m_gst_playbin), "flags", flags, NULL); + + //gstbus handler + GstBus * bus = gst_pipeline_get_bus( GST_PIPELINE(m_gst_playbin) ); + gst_bus_set_sync_handler(bus, Gst_bus_call, NULL); + gst_object_unref(bus); + + // state playing + gst_element_set_state(GST_ELEMENT(m_gst_playbin), GST_STATE_PLAYING); + + playing = true; + playstate = STATE_PLAY; + } + else + { + lt_info("%s:%s - failed to create GStreamer pipeline!, sorry we can not play\n", FILENAME, __FUNCTION__); + playing = false; + + return false; + } + + g_free(uri); + + // set buffer size + /* increase the default 2 second / 2 MB buffer limitations to 5s / 5MB */ + int m_buffer_size = 5*1024*1024; + //g_object_set(G_OBJECT(m_gst_playbin), "buffer-duration", 5LL * GST_SECOND, NULL); + g_object_set(G_OBJECT(m_gst_playbin), "buffer-size", m_buffer_size, NULL); + + return true; +} + +bool cPlayback::Play(void) +{ + lt_info( "%s:%s playing %d\n", FILENAME, __FUNCTION__, playing); + + if(playing == true) + return true; + + if(m_gst_playbin) + { + gst_element_set_state(GST_ELEMENT(m_gst_playbin), GST_STATE_PLAYING); + + playing = true; + playstate = STATE_PLAY; + } + lt_info("%s:%s playing %d\n", FILENAME, __FUNCTION__, playing); + + return playing; +} + +bool cPlayback::Stop(void) +{ + if(playing == false) + return false; + lt_info( "%s:%s playing %d\n", FILENAME, __FUNCTION__, playing); + + // stop + if(m_gst_playbin) + { + gst_element_set_state(m_gst_playbin, GST_STATE_NULL); + } + + playing = false; + + lt_info( "%s:%s playing %d\n", FILENAME, __FUNCTION__, playing); + + playstate = STATE_STOP; + + return true; +} + +bool cPlayback::SetAPid(int pid , bool /*ac3*/) +{ + lt_info("%s: pid %i\n", __func__, pid); + + int current_audio; + + if(pid != mAudioStream) + { + g_object_set (G_OBJECT (m_gst_playbin), "current-audio", pid, NULL); + printf("%s: switched to audio stream %i\n", __FUNCTION__, pid); + mAudioStream = pid; + } + + return true; +} + +void cPlayback::trickSeek(int ratio) +{ + bool validposition = false; + gint64 pos = 0; + int position; + int duration; + + if( GetPosition(position, duration) ) + { + validposition = true; + pos = position; + } + + gst_element_set_state(m_gst_playbin, GST_STATE_PLAYING); + + if (validposition) + { + if(ratio >= 0.0) + gst_element_seek(m_gst_playbin, ratio, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP), GST_SEEK_TYPE_SET, pos, GST_SEEK_TYPE_SET, -1); + else + gst_element_seek(m_gst_playbin, ratio, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP), GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, pos); + } +} + +bool cPlayback::SetSpeed(int speed) +{ + lt_info( "%s:%s speed %d\n", FILENAME, __FUNCTION__, speed); + + if(playing == false) + return false; + + if(m_gst_playbin) + { + // pause + if(speed == 0) + { + gst_element_set_state(m_gst_playbin, GST_STATE_PAUSED); + //trickSeek(0); + playstate = STATE_PAUSE; + } + // play/continue + else if(speed == 1) + { + trickSeek(1); + //gst_element_set_state(m_gst_playbin, GST_STATE_PLAYING); + // + playstate = STATE_PLAY; + } + //ff + else if(speed > 1) + { + trickSeek(speed); + // + playstate = STATE_FF; + } + //rf + else if(speed < 0) + { + trickSeek(speed); + // + playstate = STATE_REW; + } + } + + mSpeed = speed; + + return true; +} + +bool cPlayback::SetSlow(int slow) +{ + lt_info( "%s:%s playing %d\n", FILENAME, __FUNCTION__, playing); + + if(playing == false) + return false; + + if(m_gst_playbin) + { + trickSeek(0.5); + } + + playstate = STATE_SLOW; + + mSpeed = slow; + + return true; +} + +bool cPlayback::GetSpeed(int &speed) const +{ + speed = mSpeed; + + return true; +} + +// in milliseconds +bool cPlayback::GetPosition(int &position, int &duration) +{ + if(playing == false) + return false; + + //EOF + if(end_eof) + { + end_eof = 0; + return false; + } + + if(m_gst_playbin) + { + //position + GstFormat fmt = GST_FORMAT_TIME; //Returns time in nanosecs + + gint64 pts = 0; + unsigned long long int sec = 0; + + gst_element_query_position(m_gst_playbin, &fmt, &pts); + position = pts / 1000000.0; + + // duration + GstFormat fmt_d = GST_FORMAT_TIME; //Returns time in nanosecs + double length = 0; + gint64 len; + + gst_element_query_duration(m_gst_playbin, &fmt_d, &len); + length = len / 1000000.0; + if(length < 0) + length = 0; + + duration = (int)(length); + } + + return true; +} + +bool cPlayback::SetPosition(int position, bool absolute) +{ + lt_info("%s: pos %d abs %d playing %d\n", __func__, position, absolute, playing); + + if(playing == false) + return false; + + gint64 time_nanoseconds; + gint64 pos; + GstFormat fmt = GST_FORMAT_TIME; + + if(m_gst_playbin) + { + gst_element_query_position(m_gst_playbin, &fmt, &pos); + time_nanoseconds = pos + (position * 1000000.0); + if(time_nanoseconds < 0) + time_nanoseconds = 0; + + gst_element_seek(m_gst_playbin, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, time_nanoseconds, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); + } + + return true; +} + +void cPlayback::FindAllPids(int *apids, unsigned int *ac3flags, unsigned int *numpida, std::string * language) +{ + lt_info( "%s:%s\n", FILENAME, __FUNCTION__); + + if(m_gst_playbin) + { + gint i, n_audio = 0; + //GstStructure * structure = NULL; + + // get audio + g_object_get (m_gst_playbin, "n-audio", &n_audio, NULL); + printf("%s: %d audio\n", __FUNCTION__, n_audio); + + if(n_audio == 0) + return; + + for (i = 0; i < n_audio; i++) + { + // apids + apids[i]=i; + + GstPad * pad = 0; + g_signal_emit_by_name (m_gst_playbin, "get-audio-pad", i, &pad); + GstCaps * caps = gst_pad_get_negotiated_caps(pad); + if (!caps) + continue; + + GstStructure * structure = gst_caps_get_structure(caps, 0); + //const gchar *g_type = gst_structure_get_name(structure); + + //if (!structure) + //return atUnknown; + //ac3flags[0] = 0; + + // ac3flags + if ( gst_structure_has_name (structure, "audio/mpeg")) + { + gint mpegversion, layer = -1; + + if (!gst_structure_get_int (structure, "mpegversion", &mpegversion)) + //return atUnknown; + ac3flags[i] = 0; + + switch (mpegversion) + { + case 1: + /* + { + gst_structure_get_int (structure, "layer", &layer); + if ( layer == 3 ) + return atMP3; + else + return atMPEG; + ac3flags[0] = 4; + break; + } + */ + ac3flags[i] = 4; + case 2: + //return atAAC; + ac3flags[i] = 5; + case 4: + //return atAAC; + ac3flags[i] = 5; + default: + //return atUnknown; + ac3flags[i] = 0; + } + } + else if ( gst_structure_has_name (structure, "audio/x-ac3") || gst_structure_has_name (structure, "audio/ac3") ) + //return atAC3; + ac3flags[i] = 1; + else if ( gst_structure_has_name (structure, "audio/x-dts") || gst_structure_has_name (structure, "audio/dts") ) + //return atDTS; + ac3flags[i] = 6; + else if ( gst_structure_has_name (structure, "audio/x-raw-int") ) + //return atPCM; + ac3flags[i] = 0; + + gst_caps_unref(caps); + } + + // numpids + *numpida=i; + } +} + +void cPlayback::getMeta() +{ + if(playing) + return; +} + +bool cPlayback::SyncAV(void) +{ + lt_info( "%s:%s playing %d\n", FILENAME, __FUNCTION__, playing); + + if(playing == false ) + return false; + + return true; +} + +void cPlayback::RequestAbort() +{ +} + +void cPlayback::FindAllSubs(uint16_t *, unsigned short *, uint16_t *numpida, std::string *) +{ + printf("%s:%s\n", FILENAME, __func__); + *numpida = 0; +} + +void cPlayback::GetChapters(std::vector &positions, std::vector &titles) +{ + positions.clear(); + titles.clear(); +} + +bool cPlayback::SelectSubtitles(int pid) +{ + printf("%s:%s pid %i\n", FILENAME, __func__, pid); + return true; +} + +void cPlayback::GetMetadata(std::vector &keys, std::vector &values) +{ + keys.clear(); + values.clear(); +} + +void cPlayback::FindAllTeletextsubtitlePids(int *, unsigned int *numpids, std::string *, int *, int *) +{ + *numpids = 0; +} + +void cPlayback::FindAllSubtitlePids(int * /*pids*/, unsigned int *numpids, std::string * /*language*/) +{ + *numpids = 0; +} + +bool cPlayback::SetSubtitlePid(int /*pid*/) +{ + return true; +} + +void cPlayback::GetPts(uint64_t &/*pts*/) +{ +} + +bool cPlayback::SetTeletextPid(int /*pid*/) +{ + return true; +} diff --git a/generic-pc/playback_gst.h b/generic-pc/playback_gst.h new file mode 100644 index 0000000..b024f7e --- /dev/null +++ b/generic-pc/playback_gst.h @@ -0,0 +1,88 @@ +/* + * + * 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 __PLAYBACK_CS_H +#define __PLAYBACK_CS_H + +#include +#include +#include + +#include + + +typedef enum { + STATE_STOP, + STATE_PLAY, + STATE_PAUSE, + STATE_FF, + STATE_REW, + STATE_SLOW +} playstate_t; + +typedef enum { + PLAYMODE_TS = 0, + PLAYMODE_FILE, +} playmode_t; + + +class cPlayback +{ + private: + bool playing; + + int mSpeed; + int mAudioStream; + + public: + playstate_t playstate; + + cPlayback(int); + bool Open(playmode_t PlayMode); + void Close(void); + bool Start(char *filename, int vpid, int vtype, int apid, int ac3, int duration); + bool Play(void); + bool SyncAV(void); + + bool Stop(void); + bool SetAPid(int pid, bool ac3); + bool SetSubtitlePid(int pid); + bool SetTeletextPid(int pid); + + void trickSeek(int ratio); + bool SetSpeed(int speed); + bool SetSlow(int slow); + bool GetSpeed(int &speed) const; + bool GetPosition(int &position, int &duration); + void GetPts(uint64_t &pts); + bool SetPosition(int position, bool absolute = false); + void FindAllPids(int *apids, unsigned int *ac3flags, unsigned int *numpida, std::string *language); + void FindAllSubtitlePids(int *pids, unsigned int *numpids, std::string *language); + void FindAllTeletextsubtitlePids(int *pids, unsigned int *numpidt, std::string *tlanguage, int *mags, int *pages); + void RequestAbort(void); + void FindAllSubs(uint16_t *pids, unsigned short *supported, uint16_t *numpida, std::string *language); + bool SelectSubtitles(int pid); + void GetChapters(std::vector &positions, std::vector &titles); + void GetMetadata(std::vector &keys, std::vector &values); + // + ~cPlayback(); + void getMeta(); +}; + +#endif +