From 464838fd242a623f7fcae3dc31ee137f854fa364 Mon Sep 17 00:00:00 2001 From: TangoCash Date: Fri, 3 Nov 2017 12:12:32 +0100 Subject: [PATCH 01/12] align --- include/hardware_caps.h | 3 ++- libarmbox/hardware_caps.c | 2 +- libduckbox/hardware_caps.c | 16 ++++++++-------- libspark/hardware_caps.c | 4 ++-- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/include/hardware_caps.h b/include/hardware_caps.h index 592cde6..1a8952f 100644 --- a/include/hardware_caps.h +++ b/include/hardware_caps.h @@ -36,7 +36,8 @@ typedef struct hw_caps display_type_t display_type; int display_xres; /* x resolution or chars per line */ int display_yres; - int can_set_display_brightness; + int display_can_set_brightness; + int display_can_deepstandby; char boxvendor[64]; char boxname[64]; char boxarch[64]; diff --git a/libarmbox/hardware_caps.c b/libarmbox/hardware_caps.c index 5ce19c4..8a19704 100644 --- a/libarmbox/hardware_caps.c +++ b/libarmbox/hardware_caps.c @@ -34,7 +34,7 @@ hw_caps_t *get_hwcaps(void) caps.can_shutdown = 1; caps.display_xres = 16; caps.display_type = HW_DISPLAY_LINE_TEXT; - caps.can_set_display_brightness = 1; + caps.display_can_set_brightness = 1; caps.has_HDMI = 1; strcpy(caps.boxvendor, "AX-Technologies"); strcpy(caps.boxname, "HD51"); diff --git a/libduckbox/hardware_caps.c b/libduckbox/hardware_caps.c index 8ab4586..9d6e274 100644 --- a/libduckbox/hardware_caps.c +++ b/libduckbox/hardware_caps.c @@ -29,7 +29,7 @@ hw_caps_t *get_hwcaps(void) char buf[64]; int len = -1; int fd = open("/proc/stb/info/model", O_RDONLY); - caps.can_set_display_brightness = 0; + caps.display_can_set_brightness = 0; if (fd != -1) { len = read(fd, buf, sizeof(buf) - 1); close(fd); @@ -55,7 +55,7 @@ hw_caps_t *get_hwcaps(void) caps.can_cec = 1; caps.has_fan = 0; caps.has_CI = 2; - caps.can_set_display_brightness = 1; + caps.display_can_set_brightness = 1; } else if (!strncmp(buf, "ufs913", 6)) { strcpy(caps.boxvendor, "DUCKBOX"); @@ -66,7 +66,7 @@ hw_caps_t *get_hwcaps(void) caps.can_cec = 1; caps.has_fan = 0; caps.has_CI = 2; - caps.can_set_display_brightness = 1; + caps.display_can_set_brightness = 1; } else if (!strncmp(buf, "ufs922", 6)) { strcpy(caps.boxvendor, "DUCKBOX"); @@ -87,7 +87,7 @@ hw_caps_t *get_hwcaps(void) caps.can_cec = 0; caps.has_fan = 0; caps.has_CI = 2; - caps.can_set_display_brightness = 1; + caps.display_can_set_brightness = 1; } else if (!strncmp(buf, "hdbox", 5)) { strcpy(caps.boxvendor, "DUCKBOX"); @@ -273,7 +273,7 @@ hw_caps_t *get_hwcaps(void) caps.can_cec = 1; caps.has_fan = 0; caps.has_CI = 2; - caps.can_set_display_brightness = 0; + caps.display_can_set_brightness = 0; } else if ((!strncasecmp(buf, "nbox", 4)) || (!strncasecmp(buf, "adb_box", 7))) { @@ -285,7 +285,7 @@ hw_caps_t *get_hwcaps(void) caps.can_cec = 1; caps.has_fan = 1; caps.has_CI = 2; - caps.can_set_display_brightness = 1; + caps.display_can_set_brightness = 1; } else if ((!strncasecmp(buf, "sagemcom88", 10)) || (!strncasecmp(buf, "esi_88", 6)) || @@ -299,7 +299,7 @@ hw_caps_t *get_hwcaps(void) caps.can_cec = 1; caps.has_fan = 1; caps.has_CI = 0; - caps.can_set_display_brightness = 1; + caps.display_can_set_brightness = 1; } else if (!strncasecmp(buf, "dsi87", 5)) { strcpy(caps.boxvendor, "DUCKBOX"); @@ -310,7 +310,7 @@ hw_caps_t *get_hwcaps(void) caps.can_cec = 1; caps.has_fan = 0; caps.has_CI = 0; - caps.can_set_display_brightness = 0; + caps.display_can_set_brightness = 0; } else { strcpy(caps.boxvendor, "unknown"); diff --git a/libspark/hardware_caps.c b/libspark/hardware_caps.c index dd2f941..557b9e7 100644 --- a/libspark/hardware_caps.c +++ b/libspark/hardware_caps.c @@ -34,7 +34,7 @@ hw_caps_t *get_hwcaps(void) caps.can_cec = 1; caps.can_shutdown = 1; caps.display_type = HW_DISPLAY_LED_NUM; - caps.can_set_display_brightness = 0; + caps.display_can_set_brightness = 0; caps.has_HDMI = 1; caps.has_SCART = 1; caps.display_xres = 4; @@ -50,7 +50,7 @@ hw_caps_t *get_hwcaps(void) else if (val & 1) { /* VFD = 1, DVFD = 3 */ caps.display_type = HW_DISPLAY_LINE_TEXT; caps.display_xres = 8; - caps.can_set_display_brightness = 1; + caps.display_can_set_brightness = 1; } close(fd); } From 8218368064688850fe84cde4970e2e8613156935 Mon Sep 17 00:00:00 2001 From: TangoCash Date: Fri, 3 Nov 2017 21:18:53 +0100 Subject: [PATCH 02/12] update generic gstreamer --- generic-pc/Makefile.am | 4 +- generic-pc/playback_gst.h | 93 ++-- generic-pc/playback_gst_10.cpp | 924 +++++++++++++++++++++------------ 3 files changed, 658 insertions(+), 363 deletions(-) diff --git a/generic-pc/Makefile.am b/generic-pc/Makefile.am index 58f5114..11f6db1 100644 --- a/generic-pc/Makefile.am +++ b/generic-pc/Makefile.am @@ -36,7 +36,9 @@ if ENABLE_GSTREAMER_10 libgeneric_la_SOURCES += \ playback_gst_10.cpp AM_LDFLAGS += \ - -lgstreamer-1.0 + -lgstreamer-1.0 \ + -lgsttag-1.0 \ + -lgstmpegts-1.0 else libgeneric_la_SOURCES += \ playback.cpp diff --git a/generic-pc/playback_gst.h b/generic-pc/playback_gst.h index 6d78fa1..a58de78 100644 --- a/generic-pc/playback_gst.h +++ b/generic-pc/playback_gst.h @@ -26,7 +26,8 @@ #include -typedef enum { +typedef enum +{ STATE_STOP, STATE_PLAY, STATE_PAUSE, @@ -35,55 +36,67 @@ typedef enum { STATE_SLOW } playstate_t; -typedef enum { +typedef enum +{ PLAYMODE_TS = 0, PLAYMODE_FILE, } playmode_t; +struct AVFormatContext; class cPlayback { - private: - bool playing; +private: + bool playing, first; + bool decoders_closed; - int mSpeed; - int mAudioStream; + int mSpeed; + int mAudioStream; + int init_jump; - 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, std::string headers = ""); - bool Start(std::string filename, std::string headers = ""); - bool Play(void); - bool SyncAV(void); - - bool Stop(void); - bool SetAPid(int pid, bool ac3); - bool SetSubtitlePid(int pid); - bool SetTeletextPid(int pid); +public: + playstate_t playstate; - 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); - uint64_t GetReadCount(void); - void GetChapters(std::vector &positions, std::vector &titles); - void GetMetadata(std::vector &keys, std::vector &values); - // - ~cPlayback(); - void getMeta(); + cPlayback(int); + bool Open(playmode_t PlayMode); + void Close(void); + bool Start(char *filename, int vpid, int vtype, int apid, int ac3, int duration, std::string headers = ""); + bool Start(std::string filename, std::string headers = ""); + 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); + int GetAPid(void); + int GetVPid(void); + int GetSubtitlePid(void); + 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); + uint64_t GetReadCount(void); + void GetChapters(std::vector &positions, std::vector &titles); + void GetMetadata(std::vector &keys, std::vector &values); + AVFormatContext *GetAVFormatContext(); + void ReleaseAVFormatContext(); + std::string extra_headers; + std::string user_agent; + + // + ~cPlayback(); + void getMeta(); }; #endif diff --git a/generic-pc/playback_gst_10.cpp b/generic-pc/playback_gst_10.cpp index e386f12..1d5d9fb 100644 --- a/generic-pc/playback_gst_10.cpp +++ b/generic-pc/playback_gst_10.cpp @@ -46,29 +46,39 @@ static const char * FILENAME = "[playback.cpp]"; #include +#include +#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 + GST_PLAY_FLAG_VIDEO = (1 << 0), + GST_PLAY_FLAG_AUDIO = (1 << 1), + GST_PLAY_FLAG_TEXT = (1 << 2), + GST_PLAY_FLAG_VIS = (1 << 3), + GST_PLAY_FLAG_SOFT_VOLUME = (1 << 4), + GST_PLAY_FLAG_NATIVE_AUDIO = (1 << 5), + GST_PLAY_FLAG_NATIVE_VIDEO = (1 << 6), + GST_PLAY_FLAG_DOWNLOAD = (1 << 7), + GST_PLAY_FLAG_BUFFERING = (1 << 8), + GST_PLAY_FLAG_DEINTERLACE = (1 << 9), + GST_PLAY_FLAG_SOFT_COLORBALANCE = (1 << 10), + GST_PLAY_FLAG_FORCE_FILTERS = (1 << 11), } GstPlayFlags; GstElement * m_gst_playbin = NULL; GstElement * audioSink = NULL; GstElement * videoSink = NULL; + gchar * uri = NULL; -GstTagList * m_stream_tags = 0; +GstTagList * m_stream_tags = NULL; static int end_eof = 0; +#define HTTP_TIMEOUT 30 +// taken from record.h +#define REC_MAX_APIDS 20 +int real_apids[REC_MAX_APIDS]; extern GLFramebuffer *glfb; @@ -78,191 +88,323 @@ gint match_sinktype(const GValue *velement, const gchar *type) return strcmp(g_type_name(G_OBJECT_TYPE(element)), type); } +void resetPids() +{ + for (unsigned int i = 0; i < REC_MAX_APIDS; i++) { + real_apids[i] = 0; + } +} + +void processMpegTsSection(GstMpegtsSection* section) +{ + resetPids(); + int cnt = 0; + if (section->section_type == GST_MPEGTS_SECTION_PMT) { + const GstMpegtsPMT* pmt = gst_mpegts_section_get_pmt(section); + for (guint i = 0; i < pmt->streams->len; ++i) { + const GstMpegtsPMTStream* stream = static_cast(g_ptr_array_index(pmt->streams, i)); + if (stream->stream_type == 0x05 || stream->stream_type >= 0x80) { + lt_info_c( "%s:%s Audio Stream pid: %d\n", FILENAME, __FUNCTION__, stream->pid); + real_apids[cnt] = stream->pid; + cnt++; + } + } + } +} + +void playbinNotifySource(GObject *object, GParamSpec *unused, gpointer user_data) +{ + GstElement *source = NULL; + cPlayback *_this = (cPlayback*)user_data; + g_object_get(object, "source", &source, NULL); + + if (source) + { + if (g_object_class_find_property(G_OBJECT_GET_CLASS(source), "timeout") != 0) + { + GstElementFactory *factory = gst_element_get_factory(source); + if (factory) + { + const gchar *sourcename = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(factory)); + if (!strcmp(sourcename, "souphttpsrc")) + { + g_object_set(G_OBJECT(source), "timeout", HTTP_TIMEOUT, NULL); + } + } + } + if (g_object_class_find_property(G_OBJECT_GET_CLASS(source), "ssl-strict") != 0) + { + g_object_set(G_OBJECT(source), "ssl-strict", FALSE, NULL); + } + if (g_object_class_find_property(G_OBJECT_GET_CLASS(source), "user-agent") != 0 && !_this->user_agent.empty()) + { + g_object_set(G_OBJECT(source), "user-agent", _this->user_agent.c_str(), NULL); + } + if (g_object_class_find_property(G_OBJECT_GET_CLASS(source), "extra-headers") != 0 && !_this->extra_headers.empty()) + { + GstStructure *extras = gst_structure_new_empty("extras"); + size_t pos = 0; + while (pos != std::string::npos) + { + std::string name, value; + size_t start = pos; + size_t len = std::string::npos; + pos = _this->extra_headers.find('=', pos); + if (pos != std::string::npos) + { + len = pos - start; + pos++; + name = _this->extra_headers.substr(start, len); + start = pos; + len = std::string::npos; + pos = _this->extra_headers.find('&', pos); + if (pos != std::string::npos) + { + len = pos - start; + pos++; + } + value = _this->extra_headers.substr(start, len); + } + if (!name.empty() && !value.empty()) + { + GValue header; + lt_info_c( "%s:%s setting extra-header '%s:%s'\n", FILENAME, __FUNCTION__, name.c_str(), value.c_str()); + memset(&header, 0, sizeof(GValue)); + g_value_init(&header, G_TYPE_STRING); + g_value_set_string(&header, value.c_str()); + gst_structure_set_value(extras, name.c_str(), &header); + } + else + { + lt_info_c( "%s:%s Invalid header format %s\n", FILENAME, __FUNCTION__, _this->extra_headers.c_str()); + break; + } + } + if (gst_structure_n_fields(extras) > 0) + { + g_object_set(G_OBJECT(source), "extra-headers", extras, NULL); + } + gst_structure_free(extras); + } + gst_object_unref(source); + } +} + 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)) + 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); + case GST_MESSAGE_EOS: + { + g_message("End-of-stream"); + end_eof = 1; + break; + } - end_eof = 1; // NOTE: just to exit - - break; - } - - case GST_MESSAGE_INFO: + 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 ) { - 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 ( err->code == GST_STREAM_ERROR_CODEC_NOT_FOUND ) { if ( g_strrstr(sourceName, "videosink") ) - lt_info_c( "%s:%s - GST_MESSAGE_INFO: videosink\n", FILENAME, __FUNCTION__ ); //FIXME: how shall playback handle this event??? + 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(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) - { - GstMapInfo Info; - gst_buffer_map(buf_image, &Info,(GstMapFlags)( GST_MAP_READ)); - int ret = write(fd, Info.data, Info.size); - close(fd); - gst_buffer_unmap(buf_image, &Info); - 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_debug_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; + g_error_free(err); - 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)); - GValue r = G_VALUE_INIT; - gst_iterator_find_custom(children, (GCompareFunc)match_sinktype, &r, (gpointer)"GstDVBAudioSink"); - audioSink = GST_ELEMENT_CAST(g_value_dup_object (&r)); - g_value_unset (&r); - gst_iterator_find_custom(children, (GCompareFunc)match_sinktype, &r, (gpointer)"GstDVBVideoSink"); - videoSink = GST_ELEMENT_CAST(g_value_dup_object (&r)); - g_value_unset (&r); - 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: + 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(gst_structure_has_name(gst_message_get_structure(msg), "prepare-window-handle")) + 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_is_equal(m_stream_tags, result)) { - // set window id - gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(GST_MESSAGE_SRC (msg)), glfb->getWindowID()); - - // reshape window - gst_video_overlay_set_render_rectangle(GST_VIDEO_OVERLAY(GST_MESSAGE_SRC (msg)), 0, 0, glfb->getOSDWidth(), glfb->getOSDHeight()); - - // sync frames - gst_video_overlay_expose(GST_VIDEO_OVERLAY(GST_MESSAGE_SRC (msg))); + gst_tag_list_unref(tags); + gst_tag_list_unref(result); + break; } + if (m_stream_tags) + gst_tag_list_unref(m_stream_tags); + m_stream_tags = gst_tag_list_copy(result); + gst_tag_list_unref(result); + } + + const GValue *gv_image = gst_tag_list_get_value_index(tags, GST_TAG_IMAGE, 0); + if ( gv_image ) + { + GstBuffer *buf_image; + GstSample *sample; + sample = (GstSample *)g_value_get_boxed(gv_image); + buf_image = gst_sample_get_buffer(sample); + int fd = open("/tmp/.id3coverart", O_CREAT|O_WRONLY|O_TRUNC, 0644); + if (fd >= 0) + { + guint8 *data; + gsize size; + GstMapInfo map; + gst_buffer_map(buf_image, &map, GST_MAP_READ); + data = map.data; + size = map.size; + int ret = write(fd, data, size); + gst_buffer_unmap(buf_image, &map); + close(fd); + lt_info_c("%s:%s - /tmp/.id3coverart %d bytes written\n", FILENAME, __FUNCTION__, ret); + } + } + gst_tag_list_unref(tags); + lt_debug_c( "%s:%s - GST_MESSAGE_INFO: update info tags\n", FILENAME, __FUNCTION__); //FIXME: how shall playback handle this event??? + break; + } + case GST_MESSAGE_ELEMENT: + { +#if 0 + if(gst_structure_has_name(gst_message_get_structure(msg), "prepare-window-handle")) + { + // set window id + gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(GST_MESSAGE_SRC (msg)), glfb->getWindowID()); + + // reshape window + gst_video_overlay_set_render_rectangle(GST_VIDEO_OVERLAY(GST_MESSAGE_SRC (msg)), 0, 0, glfb->getOSDWidth(), glfb->getOSDHeight()); + + // sync frames + gst_video_overlay_expose(GST_VIDEO_OVERLAY(GST_MESSAGE_SRC (msg))); } #endif - break; - default: + GstMpegtsSection* section = gst_message_parse_mpegts_section(msg); + if (section) { + processMpegTsSection(section); + gst_mpegts_section_unref(section); + } + } + 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; + GValue r = { 0, }; + + 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)); + + if (gst_iterator_find_custom(children, (GCompareFunc)match_sinktype, &r, (gpointer)"GstDVBAudioSink")) + { + audioSink = GST_ELEMENT_CAST(g_value_dup_object (&r)); + g_value_unset (&r); + lt_info_c( "%s %s - audio sink created\n", FILENAME, __FUNCTION__); + } + + gst_iterator_free(children); + children = gst_bin_iterate_recurse(GST_BIN(m_gst_playbin)); + + if (gst_iterator_find_custom(children, (GCompareFunc)match_sinktype, &r, (gpointer)"GstDVBVideoSink")) + { + videoSink = GST_ELEMENT_CAST(g_value_dup_object (&r)); + g_value_unset (&r); + lt_info_c( "%s %s - video sink created\n", FILENAME, __FUNCTION__); + } + 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; + } + break; + default: + break; } return GST_BUS_DROP; @@ -270,53 +412,59 @@ GstBusSyncReply Gst_bus_call(GstBus * bus, GstMessage *msg, gpointer user_data) cPlayback::cPlayback(int num) -{ +{ lt_info( "%s:%s\n", FILENAME, __FUNCTION__); - const gchar *nano_str; - guint major, minor, micro, nano; + 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)"; + if (nano == 1) + nano_str = "(CVS)"; + else if (nano == 2) + nano_str = "(Prerelease)"; else - nano_str = ""; + nano_str = ""; - lt_info( "%s:%s - This program is linked against GStreamer %d.%d.%d %s\n", - FILENAME, __FUNCTION__, - major, minor, micro, 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; + decoders_closed = false; + first = false; } cPlayback::~cPlayback() -{ +{ lt_info( "%s:%s\n", FILENAME, __FUNCTION__); //FIXME: all deleting stuff is done in Close() + if (m_stream_tags) + gst_tag_list_unref(m_stream_tags); } //Used by Fileplay bool cPlayback::Open(playmode_t PlayMode) { lt_info("%s: PlayMode %d\n", __func__, PlayMode); + + init_jump = -1; return true; } // used by movieplay void cPlayback::Close(void) -{ +{ lt_info( "%s:%s\n", FILENAME, __FUNCTION__); Stop(); - + // disconnect bus handler if (m_gst_playbin) { @@ -326,9 +474,6 @@ void cPlayback::Close(void) 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) @@ -337,24 +482,26 @@ void cPlayback::Close(void) { 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 @@ -367,16 +514,32 @@ bool cPlayback::Start(char *filename, int /*vpid*/, int /*vtype*/, int /*apid*/, { lt_info( "%s:%s\n", FILENAME, __FUNCTION__); + if (!headers.empty()) + extra_headers = headers; + else + extra_headers.clear(); + + resetPids(); + mAudioStream = 0; - + init_jump = -1; + + gst_tag_list_unref(m_stream_tags); + m_stream_tags = NULL; + + unlink("/tmp/.id3coverart"); + //create playback path - char file[400] = {""}; bool isHTTP = false; if(!strncmp("http://", filename, 7)) { isHTTP = true; } + else if(!strncmp("https://", filename, 8)) + { + isHTTP = true; + } else if(!strncmp("file://", filename, 7)) { isHTTP = false; @@ -397,18 +560,20 @@ bool cPlayback::Start(char *filename, int /*vpid*/, int /*vtype*/, int /*apid*/, { isHTTP = true; } - else - strcat(file, "file://"); - - strcat(file, filename); - + if (isHTTP) - uri = g_uri_escape_string(filename, G_URI_RESERVED_CHARS_GENERIC_DELIMITERS, true); + uri = g_strdup_printf ("%s", filename); else uri = g_filename_to_uri(filename, NULL, NULL); - + lt_info("%s:%s - filename=%s\n", FILENAME, __FUNCTION__, filename); + guint flags = GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | \ + GST_PLAY_FLAG_TEXT | GST_PLAY_FLAG_NATIVE_VIDEO; + + /* increase the default 2 second / 2 MB buffer limitations to 5s / 5MB */ + int m_buffer_size = 5*1024*1024; + // create gst pipeline m_gst_playbin = gst_element_factory_make ("playbin", "playbin"); @@ -416,57 +581,65 @@ bool cPlayback::Start(char *filename, int /*vpid*/, int /*vtype*/, int /*apid*/, { 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; + if(isHTTP) + { + g_signal_connect (G_OBJECT (m_gst_playbin), "notify::source", G_CALLBACK (playbinNotifySource), this); + + // set buffer size + g_object_set(G_OBJECT(m_gst_playbin), "buffer-size", m_buffer_size, NULL); + g_object_set(G_OBJECT(m_gst_playbin), "buffer-duration", 5LL * GST_SECOND, NULL); + flags |= GST_PLAY_FLAG_BUFFERING; + } + + g_object_set(G_OBJECT (m_gst_playbin), "flags", flags, NULL); 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, NULL); - gst_object_unref(bus); - + gst_object_unref(bus); + + first = true; + // state playing - gst_element_set_state(m_gst_playbin, GST_STATE_PLAYING); - + if(isHTTP) + { + gst_element_set_state(GST_ELEMENT(m_gst_playbin), GST_STATE_PLAYING); + playstate = STATE_PLAY; + } + else + { + gst_element_set_state(GST_ELEMENT(m_gst_playbin), GST_STATE_PAUSED); + playstate = STATE_PAUSE; + } + 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); - + g_free(uri); + return true; } bool cPlayback::Play(void) { - lt_info( "%s:%s playing %d\n", FILENAME, __FUNCTION__, playing); + lt_info( "%s:%s playing %d\n", FILENAME, __FUNCTION__, playing); - if(playing == true) + 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; } @@ -476,11 +649,11 @@ bool cPlayback::Play(void) } bool cPlayback::Stop(void) -{ - if(playing == false) +{ + if(playing == false) return false; lt_info( "%s:%s playing %d\n", FILENAME, __FUNCTION__, playing); - + // stop if(m_gst_playbin) { @@ -488,20 +661,20 @@ bool cPlayback::Stop(void) } playing = false; - + lt_info( "%s:%s playing %d\n", FILENAME, __FUNCTION__, playing); - + playstate = STATE_STOP; return true; } -bool cPlayback::SetAPid(int pid , bool /*ac3*/) +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); @@ -514,37 +687,29 @@ bool cPlayback::SetAPid(int pid , bool /*ac3*/) void cPlayback::trickSeek(int ratio) { - bool validposition = false; + GstFormat fmt = GST_FORMAT_TIME; 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 (gst_element_query_position(m_gst_playbin, fmt, &pos)) { 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); + gst_element_seek(m_gst_playbin, ratio, fmt, (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); + gst_element_seek(m_gst_playbin, ratio, fmt, (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); +{ + lt_info( "%s:%s speed %d\n", FILENAME, __FUNCTION__, speed); - if(playing == false) + if(playing == false) return false; if(m_gst_playbin) - { + { // pause if(speed == 0) { @@ -574,6 +739,12 @@ bool cPlayback::SetSpeed(int speed) // playstate = STATE_REW; } + + if (init_jump > -1) + { + SetPosition(init_jump,true); + init_jump = -1; + } } mSpeed = speed; @@ -582,10 +753,10 @@ bool cPlayback::SetSpeed(int speed) } bool cPlayback::SetSlow(int slow) -{ - lt_info( "%s:%s playing %d\n", FILENAME, __FUNCTION__, playing); +{ + lt_info( "%s:%s playing %d\n", FILENAME, __FUNCTION__, playing); - if(playing == false) + if(playing == false) return false; if(m_gst_playbin) @@ -610,8 +781,8 @@ bool cPlayback::GetSpeed(int &speed) const // in milliseconds bool cPlayback::GetPosition(int &position, int &duration) { - if(playing == false) - return false; + if(playing == false) + return false; //EOF if(end_eof) @@ -619,18 +790,26 @@ bool cPlayback::GetPosition(int &position, int &duration) 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); + if (audioSink || videoSink) + { + g_signal_emit_by_name(audioSink ? audioSink : videoSink, "get-decoder-time", &pts); + if (!GST_CLOCK_TIME_IS_VALID(pts)) + { + lt_info( "%s - %d failed\n", __FUNCTION__, __LINE__); + } + } + else + { + if(!gst_element_query_position(m_gst_playbin, fmt, &pts)) + lt_info( "%s - %d failed\n", __FUNCTION__, __LINE__); + } position = pts / 1000000.0; - // duration GstFormat fmt_d = GST_FORMAT_TIME; //Returns time in nanosecs double length = 0; @@ -638,33 +817,46 @@ bool cPlayback::GetPosition(int &position, int &duration) gst_element_query_duration(m_gst_playbin, fmt_d, &len); length = len / 1000000.0; - if(length < 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; - + GstState state; + 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_get_state(m_gst_playbin, &state, NULL, GST_CLOCK_TIME_NONE); + + if ( (state == GST_STATE_PAUSED) && first) + { + init_jump = position; + first = false; + return false; + } + if (!absolute) + { + gst_element_query_position(m_gst_playbin, fmt, &pos); + time_nanoseconds = pos + (position * 1000000.0); + if(time_nanoseconds < 0) + time_nanoseconds = 0; + } + else + { + time_nanoseconds = position * 1000000.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); } @@ -672,72 +864,62 @@ bool cPlayback::SetPosition(int position, bool absolute) } 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); - + lt_info("%s: %d audio\n", __FUNCTION__, n_audio); + if(n_audio == 0) return; - + + language->clear(); + for (i = 0; i < n_audio; i++) { // apids - apids[i]=i; - + apids[i]= real_apids[i] ? real_apids[i] : i; + GstPad * pad = 0; g_signal_emit_by_name (m_gst_playbin, "get-audio-pad", i, &pad); + GstCaps * caps = gst_pad_get_current_caps(pad); + gst_object_unref(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; + GstTagList * tags = NULL; + gchar * g_lang = NULL; + gchar * g_codec = NULL; // 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) + 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; + case 1: + 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") ) @@ -749,26 +931,38 @@ void cPlayback::FindAllPids(int *apids, unsigned int *ac3flags, unsigned int *nu else if ( gst_structure_has_name (structure, "audio/x-raw-int") ) //return atPCM; ac3flags[i] = 0; - + gst_caps_unref(caps); + + //(ac3flags[i] > 2) ? ac3flags[i] = 1 : ac3flags[i] = 0; + + g_signal_emit_by_name (m_gst_playbin, "get-audio-tags", i, &tags); + if (tags && GST_IS_TAG_LIST(tags)) + { + if (gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &g_lang)) + { + language[i] = std::string(gst_tag_get_language_name(g_lang)).c_str(); + lt_info("%s: language:%s\n", __FUNCTION__, language[i].c_str()); + g_free(g_lang); + } + gst_tag_list_free(tags); + } } - - // numpids *numpida=i; } } void cPlayback::getMeta() { - if(playing) + if(playing) return; } bool cPlayback::SyncAV(void) { - lt_info( "%s:%s playing %d\n", FILENAME, __FUNCTION__, playing); + lt_info( "%s:%s playing %d\n", FILENAME, __FUNCTION__, playing); - if(playing == false ) + if(playing == false ) return false; return true; @@ -800,6 +994,62 @@ void cPlayback::GetMetadata(std::vector &keys, std::vector Date: Fri, 3 Nov 2017 22:25:11 +0100 Subject: [PATCH 03/12] gstreamer playback, fix possible segfault --- libarmbox/playback_gst.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libarmbox/playback_gst.cpp b/libarmbox/playback_gst.cpp index 71275f3..671973c 100644 --- a/libarmbox/playback_gst.cpp +++ b/libarmbox/playback_gst.cpp @@ -948,7 +948,12 @@ void cPlayback::FindAllPids(int *apids, unsigned int *ac3flags, unsigned int *nu { if (gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &g_lang)) { - language[i] = std::string(gst_tag_get_language_name(g_lang)).c_str(); + std::string slang; + slang = gst_tag_get_language_name(g_lang); + if (slang.empty()) + language[i] = "unk"; + else + language[i] = slang.c_str(); lt_info("%s: language:%s\n", __FUNCTION__, language[i].c_str()); g_free(g_lang); } From cccd010efbd9fd7c3bfb3d7afb662628d0a161cf Mon Sep 17 00:00:00 2001 From: TangoCash Date: Fri, 3 Nov 2017 22:30:24 +0100 Subject: [PATCH 04/12] gstreamer playback, fix possible segfault #2 --- generic-pc/playback_gst_10.cpp | 10 +++++++++- libarmbox/playback_gst.cpp | 5 ++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/generic-pc/playback_gst_10.cpp b/generic-pc/playback_gst_10.cpp index 1d5d9fb..7247865 100644 --- a/generic-pc/playback_gst_10.cpp +++ b/generic-pc/playback_gst_10.cpp @@ -941,7 +941,15 @@ void cPlayback::FindAllPids(int *apids, unsigned int *ac3flags, unsigned int *nu { if (gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &g_lang)) { - language[i] = std::string(gst_tag_get_language_name(g_lang)).c_str(); + std::string slang; + if (gst_tag_get_language_name(g_lang) != NULL) + slang = gst_tag_get_language_name(g_lang); + else + slang = g_lang; + if (slang.empty()) + language[i] = "unk"; + else + language[i] = slang.c_str(); lt_info("%s: language:%s\n", __FUNCTION__, language[i].c_str()); g_free(g_lang); } diff --git a/libarmbox/playback_gst.cpp b/libarmbox/playback_gst.cpp index 671973c..846c8bb 100644 --- a/libarmbox/playback_gst.cpp +++ b/libarmbox/playback_gst.cpp @@ -949,7 +949,10 @@ void cPlayback::FindAllPids(int *apids, unsigned int *ac3flags, unsigned int *nu if (gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &g_lang)) { std::string slang; - slang = gst_tag_get_language_name(g_lang); + if (gst_tag_get_language_name(g_lang) != NULL) + slang = gst_tag_get_language_name(g_lang); + else + slang = g_lang; if (slang.empty()) language[i] = "unk"; else From 28aa5147c6b4c6a79a2646614620565348a3cb3c Mon Sep 17 00:00:00 2001 From: TangoCash Date: Fri, 3 Nov 2017 22:35:08 +0100 Subject: [PATCH 05/12] gstreamer playback, avoid segfault --- generic-pc/playback_gst_10.cpp | 2 +- libarmbox/playback_gst.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/generic-pc/playback_gst_10.cpp b/generic-pc/playback_gst_10.cpp index 7247865..f7c0f3d 100644 --- a/generic-pc/playback_gst_10.cpp +++ b/generic-pc/playback_gst_10.cpp @@ -942,7 +942,7 @@ void cPlayback::FindAllPids(int *apids, unsigned int *ac3flags, unsigned int *nu if (gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &g_lang)) { std::string slang; - if (gst_tag_get_language_name(g_lang) != NULL) + if (gst_tag_check_language_code(g_lang)) slang = gst_tag_get_language_name(g_lang); else slang = g_lang; diff --git a/libarmbox/playback_gst.cpp b/libarmbox/playback_gst.cpp index 846c8bb..f988ecb 100644 --- a/libarmbox/playback_gst.cpp +++ b/libarmbox/playback_gst.cpp @@ -949,7 +949,7 @@ void cPlayback::FindAllPids(int *apids, unsigned int *ac3flags, unsigned int *nu if (gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &g_lang)) { std::string slang; - if (gst_tag_get_language_name(g_lang) != NULL) + if (gst_tag_check_language_code(g_lang)) slang = gst_tag_get_language_name(g_lang); else slang = g_lang; From 97f7c230e3df784f62ca618d6b1a3389b07ad669 Mon Sep 17 00:00:00 2001 From: TangoCash Date: Sat, 4 Nov 2017 11:13:48 +0100 Subject: [PATCH 06/12] gstreamer playback, cleanup, fix real pid handling --- libarmbox/playback_gst.cpp | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/libarmbox/playback_gst.cpp b/libarmbox/playback_gst.cpp index f988ecb..1f4732e 100644 --- a/libarmbox/playback_gst.cpp +++ b/libarmbox/playback_gst.cpp @@ -30,7 +30,6 @@ #include #include -#include "dmx_lib.h" #include "audio_lib.h" #include "video_lib.h" @@ -42,11 +41,9 @@ #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]"; +static const char * FILENAME = "[playback_gst.cpp]"; extern cVideo * videoDecoder; extern cAudio * audioDecoder; -extern cDemux * audioDemux; -extern cDemux * videoDemux; #include #include @@ -111,7 +108,7 @@ void processMpegTsSection(GstMpegtsSection* section) } } -void playbinNotifySource(GObject *object, GParamSpec *unused, gpointer user_data) +void playbinNotifySource(GObject *object, GParamSpec *param_spec, gpointer user_data) { GstElement *source = NULL; cPlayback *_this = (cPlayback*)user_data; @@ -189,7 +186,7 @@ void playbinNotifySource(GObject *object, GParamSpec *unused, gpointer user_data } } -GstBusSyncReply Gst_bus_call(GstBus * bus, GstMessage *msg, gpointer user_data) +GstBusSyncReply Gst_bus_call(GstBus *bus, GstMessage *msg, gpointer user_data) { gchar * sourceName; @@ -672,13 +669,19 @@ bool cPlayback::SetAPid(int pid, bool /*ac3*/) { lt_info("%s: pid %i\n", __func__, pid); - int current_audio; + int to_audio = pid; - if(pid != mAudioStream) + for (unsigned int i = 0; i < REC_MAX_APIDS; i++) { + if (real_apids[i]) + if (real_apids[i] == pid) + to_audio = i; + } + + if(to_audio != 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; + g_object_set (G_OBJECT (m_gst_playbin), "current-audio", to_audio, NULL); + printf("%s: switched to audio stream %i\n", __FUNCTION__, to_audio); + mAudioStream = to_audio; } return true; @@ -904,12 +907,11 @@ void cPlayback::FindAllPids(int *apids, unsigned int *ac3flags, unsigned int *nu GstStructure * structure = gst_caps_get_structure(caps, 0); GstTagList * tags = NULL; gchar * g_lang = NULL; - gchar * g_codec = NULL; // ac3flags if ( gst_structure_has_name (structure, "audio/mpeg")) { - gint mpegversion, layer = -1; + gint mpegversion; if (!gst_structure_get_int (structure, "mpegversion", &mpegversion)) ac3flags[i] = 0; @@ -1101,7 +1103,7 @@ int cPlayback::GetAPid(void) gint current_audio = 0; g_object_get (m_gst_playbin, "current-audio", ¤t_audio, NULL); lt_info("%s: %d audio\n", __FUNCTION__, current_audio); - return current_audio; + return real_apids[current_audio] ? real_apids[current_audio] : current_audio; } int cPlayback::GetVPid(void) From 71c9c9d8e37b6334df35706a994ab0d853d3697f Mon Sep 17 00:00:00 2001 From: TangoCash Date: Sun, 5 Nov 2017 13:54:42 +0100 Subject: [PATCH 07/12] ci: let stbhal handle close --- libdvbci/dvbci_mmi.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libdvbci/dvbci_mmi.cpp b/libdvbci/dvbci_mmi.cpp index 5ca766b..b8c2794 100644 --- a/libdvbci/dvbci_mmi.cpp +++ b/libdvbci/dvbci_mmi.cpp @@ -51,6 +51,7 @@ int eDVBCIMMISession::receivedAPDU(const unsigned char *tag, const void *data, i pMsg->MsgId = CA_MESSAGE_MSG_MMI_CLOSE; pMsg->SlotType = CA_SLOT_TYPE_CI; pMsg->Slot = slot->slot; + stopMMI(); cCA::GetInstance()->SendMessage(pMsg); } break; From dfeace50a5e25ce6503b93d6f027659ca13b243f Mon Sep 17 00:00:00 2001 From: TangoCash Date: Sun, 5 Nov 2017 14:25:01 +0100 Subject: [PATCH 08/12] armbox: tryfix cec --- libarmbox/video.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libarmbox/video.cpp b/libarmbox/video.cpp index e810efa..8bf87b1 100644 --- a/libarmbox/video.cpp +++ b/libarmbox/video.cpp @@ -994,8 +994,10 @@ void cVideo::SetCECState(bool state) usleep(10000); message.address = 0x0f; /* broadcast */ message.data[0] = CEC_MSG_ACTIVE_SOURCE; - message.data[1] = ((((int)physicalAddress >> 12) & 0xf) << 4) + (((int)physicalAddress >> 8) & 0xf); - message.data[2] = ((((int)physicalAddress >> 4) & 0xf) << 4) + (((int)physicalAddress >> 0) & 0xf); + //message.data[1] = ((((int)physicalAddress >> 12) & 0xf) << 4) + (((int)physicalAddress >> 8) & 0xf); + //message.data[2] = ((((int)physicalAddress >> 4) & 0xf) << 4) + (((int)physicalAddress >> 0) & 0xf); + message.data[1] = physicalAddress[0]; + message.data[2] = physicalAddress[1]; message.length = 3; SendCECMessage(message); } From 8886015bac8e07c5bade4188c5af1c10e6da29ce Mon Sep 17 00:00:00 2001 From: max_10 Date: Sun, 5 Nov 2017 16:02:44 +0100 Subject: [PATCH 09/12] armbox: add dvbci (thx DboxOldie) --- common/Makefile.am | 11 + common/ca.h | 2 +- common/ca_ci.cpp | 963 ++++++++++++++++++++++++-------------- common/ca_ci.h | 65 ++- generic-pc/playback.cpp | 5 + libarmbox/cs_api.h | 2 +- libarmbox/hardware_caps.c | 2 +- libdvbci/descrambler.cpp | 139 +++++- libdvbci/descrambler.h | 4 +- libdvbci/dvbci_ccmgr.cpp | 32 ++ libdvbci/dvbci_session.h | 6 +- 11 files changed, 845 insertions(+), 386 deletions(-) diff --git a/common/Makefile.am b/common/Makefile.am index 200d2f5..23fb888 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -9,13 +9,24 @@ AM_CXXFLAGS += \ -I $(top_srcdir)/libdvbci endif +if BOXTYPE_ARMBOX +AM_CXXFLAGS += \ + -I $(top_srcdir)/include \ + -I $(top_srcdir)/libdvbci +endif + if BOXTYPE_DUCKBOX libcommon_la_SOURCES = \ ca_ci.cpp else +if BOXTYPE_ARMBOX +libcommon_la_SOURCES = \ + ca_ci.cpp +else libcommon_la_SOURCES = \ ca.cpp endif +endif libcommon_la_SOURCES += \ lt_debug.cpp \ diff --git a/common/ca.h b/common/ca.h index 46e18ee..a087805 100644 --- a/common/ca.h +++ b/common/ca.h @@ -1,7 +1,7 @@ /* * dummy functions to implement ca_cs.h interface */ -#if HAVE_DUCKBOX_HARDWARE +#if HAVE_DUCKBOX_HARDWARE || HAVE_ARM_HARDWARE #include "ca_ci.h" #else #ifndef __CA_LIBTRIPLE_H_ diff --git a/common/ca_ci.cpp b/common/ca_ci.cpp index 8ea87a9..e4dc27d 100644 --- a/common/ca_ci.cpp +++ b/common/ca_ci.cpp @@ -30,18 +30,26 @@ /* for some debug > set to 1 */ #define x_debug 1 #define y_debug 0 - -#define TAG_MENU_ANSWER 0x9f880b -#define TAG_ENTER_MENU 0x9f8022 +#define z_debug 0 +#define tsb_debug 0 +#define wd_debug 0 #define lt_debug(args...) _lt_debug(TRIPLE_DEBUG_CA, this, args) static const char * FILENAME = "[ca_ci]"; +#if HAVE_DUCKBOX_HARDWARE +const char ci_path[] = "/dev/dvb/adapter0/ci%d"; +ca_slot_info_t info; +#endif +#if HAVE_ARM_HARDWARE +const char ci_path[] = "/dev/ci%d"; +#endif static bool checkLiveSlot = false; static bool CertChecked = false; static bool Cert_OK = false; static uint8_t NullPMT[50]={0x9F,0x80,0x32,0x2E,0x03,0x6E,0xA7,0x37,0x00,0x00,0x1B,0x15,0x7D,0x00,0x00,0x03,0x15,0x7E,0x00,0x00,0x03,0x15,0x7F,0x00, 0x00,0x06,0x15,0x80,0x00,0x00,0x06,0x15,0x82,0x00,0x00,0x0B,0x08,0x7B,0x00,0x00,0x05,0x09,0x42,0x00,0x00,0x06,0x15,0x81,0x00,0x00}; +static cCA* pcCAInstance = NULL; /* für callback */ /* nur diese Message wird vom CI aus neutrinoMessages.h benutzt */ @@ -57,13 +65,37 @@ void cs_register_messenger(cs_messenger messenger) return; } +cCA *CA = cCA::GetInstance(); + +cCA::cCA(void) +{ + printf("%s -> %s\n", FILENAME, __func__); +} + +cCA::~cCA() +{ + printf("%s -> %s\n", FILENAME, __func__); +} + +cCA * cCA::GetInstance() +{ + if (pcCAInstance == NULL) + { + printf("%s -> %s\n", FILENAME, __FUNCTION__); + + hw_caps_t *caps = get_hwcaps(); + pcCAInstance = new cCA(caps->has_CI); + } + return pcCAInstance; +} + bool cCA::checkQueueSize(eDVBCISlot* slot) { return (slot->sendqueue.size() > 0); } -/* for temporary testing */ -void cCA::Test(int slot, CaIdVector caids) +/* write ci info file */ +void cCA::write_ci_info(int slot, CaIdVector caids) { char buf[255]; char mname[200]; @@ -90,7 +122,7 @@ void cCA::Test(int slot, CaIdVector caids) fclose(fd); } -void cCA::DelTest(int slot) +void cCA::del_ci_info(int slot) { char fname[20]; snprintf(fname, sizeof(fname), "/tmp/ci-slot%d" , slot); @@ -149,7 +181,7 @@ eData waitData(int fd, unsigned char* buffer, int* len) struct pollfd fds; fds.fd = fd; fds.events = POLLOUT | POLLPRI | POLLIN; - retval = poll(&fds, 1, 100); + retval = poll(&fds, 1, 200); if (retval < 0) { printf("%s data error\n", FILENAME); @@ -157,6 +189,9 @@ eData waitData(int fd, unsigned char* buffer, int* len) } else if (retval == 0) { +#if wd_debug + //printf("**** wd DataTimeout\n"); +#endif return eDataTimeout; } else if (retval > 0) @@ -167,17 +202,27 @@ eData waitData(int fd, unsigned char* buffer, int* len) if (n > 0) { *len = n; +#if wd_debug + printf("**** wd DataReceived\n"); +#endif return eDataReady; } *len = 0; + printf("%s data error\n", FILENAME); return eDataError; } else if (fds.revents & POLLOUT) { +#if wd_debug + //printf("**** wd DataWrite\n"); +#endif return eDataWrite; } else if (fds.revents & POLLPRI) { +#if wd_debug + printf("**** wd StatusChanged\n"); +#endif return eDataStatusChanged; } } @@ -188,14 +233,20 @@ static bool transmitData(eDVBCISlot* slot, unsigned char* d, int len) { printf("%s -> %s len(%d)\n", FILENAME, __func__, len); -#ifdef direct_write +#if BOXMODEL_VUSOLO4K +#if y_debug + for (int i = 0; i < len; i++) + printf("%02x ", d[i]); + printf("\n"); +#endif int res = write(slot->fd, d, len); + printf("send: %d len: %d\n", res, len); free(d); if (res < 0 || res != len) { printf("error writing data to fd %d, slot %d: %m\n", slot->fd, slot->slot); - return eDataError; + return false; } #else #if y_debug @@ -208,49 +259,14 @@ static bool transmitData(eDVBCISlot* slot, unsigned char* d, int len) return true; } -static bool sendDataLast(eDVBCISlot* slot) -{ - unsigned char data[5]; - slot->pollConnection = false; - slot->DataLast = false; - data[0] = slot->slot; - data[1] = slot->connection_id; - data[2] = T_DATA_LAST; - data[3] = 1; - data[4] = slot->connection_id; -#if y_debug - printf("*** > Data Last: "); - for (int i = 0; i < 5; i++) - printf("%02x ", data[i]); - printf("\n"); -#endif - write(slot->fd, data, 5); - return true; -} - -static bool sendRCV(eDVBCISlot* slot) -{ - unsigned char send_data[5]; - slot->pollConnection = false; - slot->DataRCV = false; - send_data[0] = slot->slot; - send_data[1] = slot->connection_id; - send_data[2] = T_RCV; - send_data[3] = 1; - send_data[4] = slot->connection_id; -#if y_debug - printf("*** > T_RCV: "); - for (int i = 0; i < 5; i++) - printf("%02x ", send_data[i]); - printf("\n"); -#endif - write(slot->fd, send_data, 5); - return true; -} - //send some data on an fd, for a special slot and connection_id eData sendData(eDVBCISlot* slot, unsigned char* data, int len) { +#if HAVE_ARM_HARDWARE + unsigned char *d = (unsigned char*) malloc(len); + memcpy(d, data, len); + transmitData(slot, d, len); +#else // only poll connection if we are not awaiting an answer slot->pollConnection = false; @@ -291,10 +307,13 @@ eData sendData(eDVBCISlot* slot, unsigned char* data, int len) len += 7; transmitData(slot, d, len); } +#endif return eDataReady; } +#if HAVE_DUCKBOX_HARDWARE + //send a transport connection create request bool sendCreateTC(eDVBCISlot* slot) { @@ -312,13 +331,53 @@ bool sendCreateTC(eDVBCISlot* slot) return true; } +static bool sendDataLast(eDVBCISlot* slot) +{ + unsigned char data[5]; + slot->pollConnection = false; + slot->DataLast = false; + data[0] = slot->slot; + data[1] = slot->connection_id; + data[2] = T_DATA_LAST; + data[3] = 1; + data[4] = slot->connection_id; +#if tsb_debug + printf("*** > Data Last: "); + for (int i = 0; i < 5; i++) + printf("%02x ", data[i]); + printf("\n"); +#endif + write(slot->fd, data, 5); + return true; +} + +static bool sendRCV(eDVBCISlot* slot) +{ + unsigned char send_data[5]; + slot->pollConnection = false; + slot->DataRCV = false; + send_data[0] = slot->slot; + send_data[1] = slot->connection_id; + send_data[2] = T_RCV; + send_data[3] = 1; + send_data[4] = slot->connection_id; +#if tsb_debug + printf("*** > T_RCV: "); + for (int i = 0; i < 5; i++) + printf("%02x ", send_data[i]); + printf("\n"); +#endif + write(slot->fd, send_data, 5); + return true; +} + void cCA::process_tpdu(eDVBCISlot* slot, unsigned char tpdu_tag, __u8* data, int asn_data_length, int /*con_id*/) { switch (tpdu_tag) { case T_C_T_C_REPLY: -#if y_debug - printf("%s %s Got CTC Replay (slot %d, con %d)\n", FILENAME, __FUNCTION__, slot->slot, slot->connection_id); +#if x_debug + printf("%s -> %s > Got CTC Replay (slot %d, con %d)\n", FILENAME, __FUNCTION__, slot->slot, slot->connection_id); #endif /*answer with data last (and if we have with data) --> DataLast flag will be generated in next loop from received APDU*/ @@ -348,8 +407,8 @@ void cCA::process_tpdu(eDVBCISlot* slot, unsigned char tpdu_tag, __u8* data, int /* single package */ if (slot->receivedData == NULL) { - printf("%s -> single package\n", FILENAME); -#if y_debug + printf("%s -> %s > single package\n", FILENAME, __func__); +#if z_debug printf("%s -> calling receiveData with data (len %d)\n", FILENAME, asn_data_length); for (int i = 0; i < asn_data_length; i++) printf("%02x ", data[i]); @@ -372,7 +431,7 @@ void cCA::process_tpdu(eDVBCISlot* slot, unsigned char tpdu_tag, __u8* data, int slot->receivedData = new_data_buffer; memcpy(slot->receivedData + slot->receivedLen, data, asn_data_length); slot->receivedLen = new_data_length; -#if y_debug +#if z_debug printf("%s -> calling receiveData with data (len %d)\n", FILENAME, asn_data_length); for (int i = 0; i < slot->receivedLen; i++) printf("%02x ", slot->receivedData[i]); @@ -402,7 +461,7 @@ void cCA::process_tpdu(eDVBCISlot* slot, unsigned char tpdu_tag, __u8* data, int if (!slot->DataLast) { slot->DataLast = true; -#if y_debug +#if tsb_debug printf("**** > T_SB\n"); #endif } @@ -413,13 +472,14 @@ void cCA::process_tpdu(eDVBCISlot* slot, unsigned char tpdu_tag, __u8* data, int printf("%s unhandled tpdu_tag 0x%0x\n", FILENAME, tpdu_tag); } } +#endif bool cCA::SendMessage(const CA_MESSAGE *msg) { lt_debug("%s\n", __func__); if(cam_messenger) cam_messenger(EVT_CA_MESSAGE, (uint32_t) msg); -#if y_debug +#if z_debug printf("*******Message\n"); printf("msg: %p\n", msg); printf("MSGID: %x\n", msg->MsgId); @@ -547,77 +607,6 @@ bool cCA::ModulePresent(enum CA_SLOT_TYPE, uint32_t slot) return false; } -void cCA::ModuleReset(enum CA_SLOT_TYPE, uint32_t slot) -{ - printf("%s -> %s\n", FILENAME, __func__); - - std::list::iterator it; - bool haveFound = false; - - for (it = slot_data.begin(); it != slot_data.end(); ++it) - { - if ((*it)->slot == slot) - { - haveFound = true; - break; - } - } - if (haveFound) - { - (*it)->status = eStatusReset; - usleep(200000); - if ((*it)->hasCCManager) - (*it)->ccmgrSession->ci_ccmgr_doClose((eDVBCISlot*)(*it)); - eDVBCISession::deleteSessions((eDVBCISlot*)(*it)); - (*it)->mmiSession = NULL; - (*it)->hasMMIManager = false; - (*it)->hasCAManager = false; - (*it)->hasCCManager = false; - (*it)->ccmgr_ready = false; - (*it)->hasDateTime = false; - (*it)->hasAppManager = false; - (*it)->mmiOpened = false; - (*it)->camIsReady = false; - - (*it)->DataLast = false; - (*it)->DataRCV = false; - (*it)->SidBlackListed = false; - (*it)->bsids.clear(); - - (*it)->counter = 0; - (*it)->init = false; - (*it)->pollConnection = false; - sprintf((*it)->name, "unknown module %d", (*it)->slot); - (*it)->cam_caids.clear(); - - (*it)->newCapmt = false; - (*it)->multi = false; - for (int j = 0; j < CI_MAX_MULTI; j++) - { - (*it)->SID[j] = 0; - (*it)->recordUse[j] = false; - (*it)->liveUse[j] = false; - } - (*it)->TP = 0; - (*it)->ci_use_count = 0; - (*it)->pmtlen = 0; - (*it)->source = TUNER_A; - (*it)->camask = 0; - memset((*it)->pmtdata, 0, sizeof((*it)->pmtdata)); - - while((*it)->sendqueue.size()) - { - delete [] (*it)->sendqueue.top().data; - (*it)->sendqueue.pop(); - } - - if (ioctl((*it)->fd, CA_RESET, (*it)->slot) < 0) - printf("IOCTL CA_RESET failed for slot %d\n", slot); - usleep(200000); - (*it)->status = eStatusNone; - } -} - int cCA::GetCAIDS(CaIdVector &Caids) { std::list::iterator it; @@ -668,7 +657,7 @@ bool cCA::StopRecordCI( u64 TP, u16 SID, u8 source, u32 calen) return false; } -SlotIt cCA::FindFreeSlot(u64 TP, u8 source, u16 SID, ca_map_t camap, unsigned char scrambled) +SlotIt cCA::FindFreeSlot(u64 TP, u8 source, u16 SID, ca_map_t camap, u8 scrambled) { printf("%s -> %s\n", FILENAME, __func__); std::list::iterator it; @@ -789,7 +778,7 @@ bool cCA::SendCAPMT(u64 tpid, u8 source, u8 camask, const unsigned char * cabuf, { u16 SID = (u16)(tpid & 0xFFFF); u64 TP = tpid >> 16; - unsigned int i = 0; + u32 i = 0; bool sid_found = false; bool recordUse_found = false; printf("%s -> %s\n", FILENAME, __func__); @@ -822,13 +811,13 @@ bool cCA::SendCAPMT(u64 tpid, u8 source, u8 camask, const unsigned char * cabuf, return true; SlotIt It = FindFreeSlot(TP, source, SID, cm, scrambled); - if ((*It)) + if (It != slot_data.end()) { printf("Slot: %d\n", (*It)->slot); SlotIt It2 = GetSlot(!(*It)->slot); /* only if 2nd CI is present */ - if ((*It2)) + if (It2 != slot_data.end()) { if (source == (*It2)->source && (*It2)->TP) { @@ -893,6 +882,10 @@ bool cCA::SendCAPMT(u64 tpid, u8 source, u8 camask, const unsigned char * cabuf, (*It)->newCapmt = true; } +#if HAVE_ARM_HARDWARE + if ((*It)->newCapmt) + extractPids((eDVBCISlot*)(*It)); +#endif if ((*It)->scrambled && !(*It)->SidBlackListed) { for (int j = 0; j < CI_MAX_MULTI; j++) @@ -917,6 +910,26 @@ bool cCA::SendCAPMT(u64 tpid, u8 source, u8 camask, const unsigned char * cabuf, } else { +#if HAVE_ARM_HARDWARE + std::list::iterator it; + recordUse_found = false; + for (it = slot_data.begin(); it != slot_data.end(); ++it) + { + if ((*it)->source == source) + { + for (int j = 0; j < CI_MAX_MULTI; j++) + { + if ((*it)->recordUse[j]) + recordUse_found = true; + } + if (!recordUse_found) + { + printf("Slot: %d Change Input to Tuner: %d\n", (*it)->slot, (*it)->source); + setInputSource((eDVBCISlot*)(*it), false); + } + } + } +#endif printf("No free ci-slot\n"); } #if x_debug @@ -937,103 +950,42 @@ bool cCA::SendCAPMT(u64 tpid, u8 source, u8 camask, const unsigned char * cabuf, return true; } -cCA::cCA(int Slots) +#if HAVE_ARM_HARDWARE +void cCA::extractPids(eDVBCISlot* slot) { - printf("%s -> %s %d\n", FILENAME, __func__, Slots); + u32 prg_info_len; + u32 es_info_len = 0; + u16 pid; + u8 * data = slot->pmtdata; + u32 len = slot->pmtlen; + int pos = 3; - int fd, i; - char filename[128]; - num_slots = Slots; + slot->pids.clear(); + + if (!(data[pos] & 0x80)) + pos += 5; + else + pos += ((data[pos] & 0x7F) + 5); - for (i = 0; i < Slots; i++) + prg_info_len = ((data[pos] << 8) | data[pos + 1]) & 0xFFF; + pos += prg_info_len + 2; + + for (u32 i = pos; i < len; i += es_info_len + 5) { + pid = (data[i+1] << 8 | data[i+2]) & 0x1FFF; + es_info_len = ((data[i + 3] << 8) | data[i + 4]) & 0xfff; + slot->pids.push_back(pid); + } + + if (slot->pids.size()) { - sprintf(filename, "/dev/dvb/adapter0/ci%d", i); - fd = open(filename, O_RDWR | O_NONBLOCK); - if (fd < 0) - { - printf("failed to open %s ->%m", filename); - } - eDVBCISlot* slot = (eDVBCISlot*) malloc(sizeof(eDVBCISlot)); - slot->slot = i; - slot->fd = fd; - slot->connection_id = 0; - slot->status = eStatusNone; - slot->receivedLen = 0; - slot->receivedData = NULL; - slot->pClass = this; - slot->pollConnection = false; - slot->camIsReady = false; - slot->hasMMIManager = false; - slot->hasCAManager = false; - slot->hasCCManager = false; - slot->ccmgr_ready = false; - slot->hasDateTime = false; - slot->hasAppManager = false; - slot->mmiOpened = false; - - slot->newCapmt = false; - slot->multi = false; - for (int j = 0; j < CI_MAX_MULTI; j++) - { - slot->SID[j] = 0; - slot->recordUse[j] = false; - slot->liveUse[j] = false; - } - slot->TP = 0; - slot->ci_use_count = 0; - slot->pmtlen = 0; - slot->source = TUNER_A; - slot->camask = 0; - memset(slot->pmtdata, 0, sizeof(slot->pmtdata)); - - slot->DataLast = false; - slot->DataRCV = false; - slot->SidBlackListed = false; - - slot->counter = 0; - slot->init = false; - sprintf(slot->name, "unknown module %d", i); - - slot->private_data = NULL; - - slot_data.push_back(slot); - /* now reset the slot so the poll pri can happen in the thread */ - if (ioctl(fd, CA_RESET, i) < 0) - printf("IOCTL CA_RESET failed for slot %p\n", slot); - /* create a thread for each slot */ - if (fd > 0) - { - if (pthread_create(&slot->slot_thread, 0, execute_thread, (void*)slot)) - { - printf("pthread_create"); - } - } + slot->newPids = true; + printf("pids: "); + for (u32 i = 0; i < slot->pids.size(); i++) + printf("%04x ", slot->pids[i]); + printf("\n"); } } - -cCA::~cCA() -{ - printf("%s -> %s\n", FILENAME, __func__); -} - -static cCA* pcCAInstance = NULL; - -cCA * cCA::GetInstance() -{ - if (pcCAInstance == NULL) - { - printf("%s -> %s\n", FILENAME, __FUNCTION__); - - hw_caps_t *caps = get_hwcaps(); - pcCAInstance = new cCA(caps->has_CI); - } - return pcCAInstance; -} - -cCA::cCA(void) -{ - printf("%s -> %s\n", FILENAME, __func__); -} +#endif void cCA::setSource(eDVBCISlot* slot) { @@ -1062,14 +1014,416 @@ void cCA::setSource(eDVBCISlot* slot) } } +#if HAVE_ARM_HARDWARE +static std::string getTunerLetter(int number) { return std::string(1, char(65 + number)); } + +void cCA::setInputs() +{ + char input[64]; + char choices[64]; + FILE * fd = 0; + + for (int number = 0; number < 4; number++) // tuner A to D, input 0 to 3 + { + snprintf(choices, 64, "/proc/stb/tsmux/input%d_choices", number); + if(access(choices, R_OK) < 0) + { + printf("no choices for input%d\n", number); + continue; + //break; + } + snprintf(input, 64, "/proc/stb/tsmux/input%d", number); + fd = fopen(input, "wb"); + if (fd) + { + printf("set input%d to tuner %s\n", number, getTunerLetter(number).c_str()); + fprintf(fd, getTunerLetter(number).c_str()); + } + else + { + printf("no input%d\n", number); + } + } +} + +void cCA::setInputSource(eDVBCISlot* slot, bool ci) +{ + char buf[64]; + snprintf(buf, 64, "/proc/stb/tsmux/input%d", slot->source); + FILE *input = fopen(buf, "wb"); + + if (input > (void*)0) + { + if (ci) + { + switch (slot->slot) + { + case 0: + fprintf(input, "CI0"); + break; + case 1: + fprintf(input, "CI1"); + break; + } + } + else + { + switch (slot->source) + { + case TUNER_A: + fprintf(input, "A"); + break; + case TUNER_B: + fprintf(input, "B"); + break; + case TUNER_C: + fprintf(input, "C"); + break; + case TUNER_D: + fprintf(input, "D"); + break; + } + } + fclose(input); + } +} +#endif + +cCA::cCA(int Slots) +{ + printf("%s -> %s %d\n", FILENAME, __func__, Slots); + + num_slots = Slots; +#if HAVE_ARM_HARDWARE + setInputs(); +#endif + + for (int i = 0; i < Slots; i++) + { + eDVBCISlot* slot = (eDVBCISlot*) malloc(sizeof(eDVBCISlot)); + slot->slot = i; + slot->fd = -1; + slot->connection_id = 0; + slot->status = eStatusNone; + slot->receivedLen = 0; + slot->receivedData = NULL; + slot->pClass = this; + slot->pollConnection = false; + slot->camIsReady = false; + slot->hasMMIManager = false; + slot->hasCAManager = false; + slot->hasCCManager = false; + slot->ccmgr_ready = false; + slot->hasDateTime = false; + slot->hasAppManager = false; + slot->mmiOpened = false; + + slot->newPids = false; + slot->newCapmt = false; + slot->multi = false; + for (int j = 0; j < CI_MAX_MULTI; j++) + { + slot->SID[j] = 0; + slot->recordUse[j] = false; + slot->liveUse[j] = false; + } + slot->TP = 0; + slot->ci_use_count = 0; + slot->pmtlen = 0; + slot->source = TUNER_A; + slot->camask = 0; + memset(slot->pmtdata, 0, sizeof(slot->pmtdata)); + + slot->DataLast = false; + slot->DataRCV = false; + slot->SidBlackListed = false; + + slot->counter = 0; + slot->init = false; + sprintf(slot->name, "unknown module %d", i); + + slot->private_data = NULL; + + slot_data.push_back(slot); + + sprintf(slot->ci_dev, ci_path, i); + slot->fd = open(slot->ci_dev, O_RDWR | O_NONBLOCK | O_CLOEXEC); + if (slot->fd < 0) + { + printf("failed to open %s ->%m", slot->ci_dev); + } +#if HAVE_DUCKBOX_HARDWARE + /* now reset the slot so the poll pri can happen in the thread */ + if (ioctl(slot->fd, CA_RESET, i) < 0) + printf("IOCTL CA_RESET failed for slot %p\n", slot); +#else + ioctl(slot->fd, 0); +#endif + usleep(200000); + /* create a thread for each slot */ + if (slot->fd > 0) + { + if (pthread_create(&slot->slot_thread, 0, execute_thread, (void*)slot)) + { + printf("pthread_create"); + } + } + } +} + +void cCA::ModuleReset(enum CA_SLOT_TYPE, uint32_t slot) +{ + printf("%s -> %s\n", FILENAME, __func__); + + std::list::iterator it; + bool haveFound = false; + + for (it = slot_data.begin(); it != slot_data.end(); ++it) + { + if ((*it)->slot == slot) + { + haveFound = true; + break; + } + } + if (haveFound) + { + (*it)->status = eStatusReset; + usleep(200000); + if ((*it)->hasCCManager) + (*it)->ccmgrSession->ci_ccmgr_doClose((eDVBCISlot*)(*it)); + eDVBCISession::deleteSessions((eDVBCISlot*)(*it)); + (*it)->mmiSession = NULL; + (*it)->hasMMIManager = false; + (*it)->hasCAManager = false; + (*it)->hasCCManager = false; + (*it)->ccmgr_ready = false; + (*it)->hasDateTime = false; + (*it)->hasAppManager = false; + (*it)->mmiOpened = false; + (*it)->camIsReady = false; + + (*it)->DataLast = false; + (*it)->DataRCV = false; + (*it)->SidBlackListed = false; + (*it)->bsids.clear(); + + (*it)->counter = 0; + (*it)->init = false; + (*it)->pollConnection = false; + sprintf((*it)->name, "unknown module %d", (*it)->slot); + (*it)->cam_caids.clear(); + + (*it)->newPids = false; + (*it)->newCapmt = false; + (*it)->multi = false; + for (int j = 0; j < CI_MAX_MULTI; j++) + { + (*it)->SID[j] = 0; + (*it)->recordUse[j] = false; + (*it)->liveUse[j] = false; + } + (*it)->TP = 0; + (*it)->ci_use_count = 0; + (*it)->pmtlen = 0; + (*it)->source = TUNER_A; + (*it)->camask = 0; + memset((*it)->pmtdata, 0, sizeof((*it)->pmtdata)); + + while((*it)->sendqueue.size()) + { + delete [] (*it)->sendqueue.top().data; + (*it)->sendqueue.pop(); + } + +#if HAVE_DUCKBOX_HARDWARE + if (ioctl((*it)->fd, CA_RESET, (*it)->slot) < 0) + printf("IOCTL CA_RESET failed for slot %d\n", slot); +#else + ioctl((*it)->fd, 0); +#endif + usleep(200000); + (*it)->status = eStatusNone; + } +} + +void cCA::ci_inserted(eDVBCISlot* slot) +{ + printf("1. cam (%d) status changed ->cam now present\n", slot->slot); + + slot->mmiSession = NULL; + slot->hasMMIManager = false; + slot->hasCAManager = false; + slot->hasDateTime = false; + slot->hasAppManager = false; + slot->mmiOpened = false; + slot->init = false; + sprintf(slot->name, "unknown module %d", slot->slot); +#if HAVE_DUCKBOX_HARDWARE + slot->status = eStatusNone; +#else + slot->status = eStatusWait; + slot->connection_id = slot->slot + 1; +#endif + /* Send a message to Neutrino cam_menu handler */ + CA_MESSAGE* pMsg = (CA_MESSAGE*) malloc(sizeof(CA_MESSAGE)); + memset(pMsg, 0, sizeof(CA_MESSAGE)); + pMsg->MsgId = CA_MESSAGE_MSG_INSERTED; + pMsg->SlotType = CA_SLOT_TYPE_CI; + pMsg->Slot = slot->slot; + SendMessage(pMsg); + + slot->camIsReady = true; +} + +void cCA::ci_removed(eDVBCISlot* slot) +{ + printf("cam (%d) status changed ->cam now _not_ present\n", slot->slot); + if (slot->hasCCManager) + slot->ccmgrSession->ci_ccmgr_doClose(slot); + eDVBCISession::deleteSessions(slot); + slot->mmiSession = NULL; + slot->hasMMIManager = false; + slot->hasCAManager = false; + slot->hasCCManager = false; + slot->ccmgr_ready = false; + slot->hasDateTime = false; + slot->hasAppManager = false; + slot->mmiOpened = false; + slot->init = false; + + slot->DataLast = false; + slot->DataRCV = false; + slot->SidBlackListed = false; + slot->bsids.clear(); + + slot->counter = 0; + slot->pollConnection = false; + sprintf(slot->name, "unknown module %d", slot->slot); + slot->status = eStatusNone; + slot->cam_caids.clear(); + + slot->newPids = false; + slot->newCapmt = false; + slot->multi = false; + for (int j = 0; j < CI_MAX_MULTI; j++) + { + slot->SID[j] = 0; + slot->recordUse[j] = false; + slot->liveUse[j] = false; + } + slot->TP = 0; + slot->ci_use_count = 0; + slot->pmtlen = 0; + slot->source = TUNER_A; + slot->camask = 0; + memset(slot->pmtdata, 0, sizeof(slot->pmtdata)); + + /* delete ci info file */ + del_ci_info(slot->slot); + /* Send a message to Neutrino cam_menu handler */ + CA_MESSAGE* pMsg = (CA_MESSAGE*) malloc(sizeof(CA_MESSAGE)); + memset(pMsg, 0, sizeof(CA_MESSAGE)); + pMsg->MsgId = CA_MESSAGE_MSG_REMOVED; + pMsg->SlotType = CA_SLOT_TYPE_CI; + pMsg->Slot = slot->slot; + SendMessage(pMsg); + + while(slot->sendqueue.size()) + { + delete [] slot->sendqueue.top().data; + slot->sendqueue.pop(); + } + slot->camIsReady = false; + usleep(100000); +} + void cCA::slot_pollthread(void *c) { - ca_slot_info_t info; unsigned char data[1024 * 4]; eDVBCISlot* slot = (eDVBCISlot*) c; while (1) { +#if HAVE_ARM_HARDWARE /* Armbox */ + int len = 1024 *4; + eData status; + + switch (slot->status) + { + case eStatusReset: + while (slot->status == eStatusReset) + { + usleep(1000); + } + break; + case eStatusNone: + { + status = waitData(slot->fd, data, &len); + if (status == eDataReady) + { + if (!slot->camIsReady) + { +#if y_debug +// test was kommt + if (len) { + printf("1. received : > "); + for (int i = 0; i < len; i++) + printf("%02x ", data[i]); + printf("\n"); + } +#endif + ci_inserted(slot); + goto FROM_FIRST; + } + } + } /* case statusnone */ + break; + case eStatusWait: + { + status = waitData(slot->fd, data, &len); +FROM_FIRST: + if (status == eDataReady) + { + slot->pollConnection = false; + if (len) + { + eDVBCISession::receiveData(slot, data, len); + eDVBCISession::pollAll(); + } + } /*if data ready */ + else if (status == eDataWrite) + { + /* only writing any data here while status = eDataWrite */ + if (!slot->sendqueue.empty()) + { + const queueData &qe = slot->sendqueue.top(); + int res = write(slot->fd, qe.data, qe.len); + if (res >= 0 && (unsigned int)res == qe.len) + { + delete [] qe.data; + slot->sendqueue.pop(); + } + else + { + printf("r = %d, %m\n", res); + } + } + } + else if (status == eDataStatusChanged) + { + if (slot->camIsReady) + { + ci_removed(slot); + } + } + } + break; + default: + printf("unknown state %d\n", slot->status); + break; + } /* switch(slot->status) */ +#else /* Duckbox */ int len = 1024 *4; unsigned char* d; eData status; @@ -1089,7 +1443,6 @@ void cCA::slot_pollthread(void *c) if (sendCreateTC(slot)) { slot->status = eStatusWait; - slot->camIsReady = true; } else { @@ -1111,32 +1464,7 @@ void cCA::slot_pollthread(void *c) if (info.flags & CA_CI_MODULE_READY) { - printf("1. cam (%d) status changed ->cam now present\n", slot->slot); - - slot->mmiSession = NULL; - slot->hasMMIManager = false; - slot->hasCAManager = false; - slot->hasDateTime = false; - slot->hasAppManager = false; - slot->mmiOpened = false; - slot->init = false; - sprintf(slot->name, "unknown module %d", slot->slot); - slot->status = eStatusNone; - - /* Send a message to Neutrino cam_menu handler */ - CA_MESSAGE* pMsg = (CA_MESSAGE*) malloc(sizeof(CA_MESSAGE)); - memset(pMsg, 0, sizeof(CA_MESSAGE)); - pMsg->MsgId = CA_MESSAGE_MSG_INSERTED; - pMsg->SlotType = CA_SLOT_TYPE_CI; - pMsg->Slot = slot->slot; - SendMessage(pMsg); - - slot->camIsReady = true; - //setSource(slot); - } - else - { - //noop + ci_inserted(slot); } } } @@ -1149,7 +1477,7 @@ void cCA::slot_pollthread(void *c) { slot->pollConnection = false; d = data; -#if y_debug +#if z_debug if ((len == 6 && d[4] == 0x80) || len > 6) { printf("slot: %d con-id: %d tpdu-tag: %02X len: %d\n", d[0], d[1], d[2], len); printf("received data: >"); @@ -1178,13 +1506,13 @@ void cCA::slot_pollthread(void *c) break; } slot->connection_id = d[1 + length_field_len]; -#if y_debug +#if z_debug printf("Setting connection_id from received data to %d\n", slot->connection_id); #endif d += 1 + length_field_len + 1; data_length -= (1 + length_field_len + 1); asn_data_length--; -#if y_debug +#if z_debug printf("****tpdu_tag: 0x%02X\n", tpdu_tag); #endif process_tpdu(slot, tpdu_tag, d, asn_data_length, slot->connection_id); @@ -1239,91 +1567,9 @@ void cCA::slot_pollthread(void *c) printf("flags %d %d %d ->slot %d\n", info.flags, CA_CI_MODULE_READY, info.flags & CA_CI_MODULE_READY, slot->slot); - if ((slot->camIsReady == false) && (info.flags & CA_CI_MODULE_READY)) + if ((slot->camIsReady) && (!(info.flags & CA_CI_MODULE_READY))) { - printf("2. cam (%d) status changed ->cam now present\n", slot->slot); - - slot->mmiSession = NULL; - slot->hasMMIManager = false; - slot->hasCAManager = false; - slot->hasCCManager = false; - slot->ccmgr_ready = false; - slot->hasDateTime = false; - slot->hasAppManager = false; - slot->mmiOpened = false; - slot->init = false; - sprintf(slot->name, "unknown module %d", slot->slot); - slot->status = eStatusNone; - - /* Send a message to Neutrino cam_menu handler */ - CA_MESSAGE* pMsg = (CA_MESSAGE*) malloc(sizeof(CA_MESSAGE)); - memset(pMsg, 0, sizeof(CA_MESSAGE)); - pMsg->MsgId = CA_MESSAGE_MSG_INSERTED; - pMsg->SlotType = CA_SLOT_TYPE_CI; - pMsg->Slot = slot->slot; - SendMessage(pMsg); - - slot->camIsReady = true; - } - else if ((slot->camIsReady == true) && (!(info.flags & CA_CI_MODULE_READY))) - { - printf("cam (%d) status changed ->cam now _not_ present\n", slot->slot); - if (slot->hasCCManager) - slot->ccmgrSession->ci_ccmgr_doClose(slot); - eDVBCISession::deleteSessions(slot); - slot->mmiSession = NULL; - slot->hasMMIManager = false; - slot->hasCAManager = false; - slot->hasCCManager = false; - slot->ccmgr_ready = false; - slot->hasDateTime = false; - slot->hasAppManager = false; - slot->mmiOpened = false; - slot->init = false; - - slot->DataLast = false; - slot->DataRCV = false; - slot->SidBlackListed = false; - slot->bsids.clear(); - - slot->counter = 0; - slot->pollConnection = false; - sprintf(slot->name, "unknown module %d", slot->slot); - slot->status = eStatusNone; - slot->cam_caids.clear(); - - slot->newCapmt = false; - slot->multi = false; - for (int j = 0; j < CI_MAX_MULTI; j++) - { - slot->SID[j] = 0; - slot->recordUse[j] = false; - slot->liveUse[j] = false; - } - slot->TP = 0; - slot->ci_use_count = 0; - slot->pmtlen = 0; - slot->source = TUNER_A; - slot->camask = 0; - memset(slot->pmtdata, 0, sizeof(slot->pmtdata)); - - /* temporary : delete testfile */ - DelTest(slot->slot); - /* Send a message to Neutrino cam_menu handler */ - CA_MESSAGE* pMsg = (CA_MESSAGE*) malloc(sizeof(CA_MESSAGE)); - memset(pMsg, 0, sizeof(CA_MESSAGE)); - pMsg->MsgId = CA_MESSAGE_MSG_REMOVED; - pMsg->SlotType = CA_SLOT_TYPE_CI; - pMsg->Slot = slot->slot; - SendMessage(pMsg); - - while(slot->sendqueue.size()) - { - delete [] slot->sendqueue.top().data; - slot->sendqueue.pop(); - } - slot->camIsReady = false; - usleep(100000); + ci_removed(slot); } } } @@ -1331,8 +1577,8 @@ void cCA::slot_pollthread(void *c) default: printf("unknown state %d\n", slot->status); break; - } - + } /* switch(slot->status) */ +#endif /* end Duckbox */ if (slot->hasCAManager && slot->hasAppManager && !slot->init) { slot->init = true; @@ -1347,8 +1593,8 @@ void cCA::slot_pollthread(void *c) } printf("\n"); - /* temporary : write testfile */ - Test(slot->slot, slot->cam_caids); + /* write ci info file */ + write_ci_info(slot->slot, slot->cam_caids); /* Send a message to Neutrino cam_menu handler */ CA_MESSAGE* pMsg = (CA_MESSAGE*) malloc(sizeof(CA_MESSAGE)); @@ -1372,8 +1618,6 @@ void cCA::slot_pollthread(void *c) } } -cCA *CA = cCA::GetInstance(); - bool cCA::SendCaPMT(eDVBCISlot* slot) { printf("%s -> %s\n", FILENAME, __func__); @@ -1395,6 +1639,9 @@ bool cCA::SendCaPMT(eDVBCISlot* slot) if (slot->fd > 0) { +#if HAVE_ARM_HARDWARE + setInputSource(slot, true); +#endif setSource(slot); } return true; @@ -1486,3 +1733,33 @@ void cCA::setCheckLiveSlot(int check) else checkLiveSlot = false; } + +void cCA::SetTSClock(u32 Speed) +{ +/* TODO: + * For now using the coolstream values from neutrino cam_menu + * where 6 ( == 6000000 Hz ) means : 'normal' + * and other values mean : 'high' + * also only ci0 will be changed + * for more than one ci slot code must be changed in neutrino cam_menu + * and in zapit where ci_clock is set during start. + * and here too. + * On the other hand: or ci_clock will be set here for all ci slots ???? + */ + char buf[64]; + snprintf(buf, 64, "/proc/stb/tsmux/ci%d_tsclk", 0); + FILE *ci = fopen(buf, "wb"); + printf("%s -> %s to: %s\n", FILENAME, __func__, Speed > 6 * 1000000 ? "high" : "normal"); + if (ci) + { + if (Speed > 6 * 1000000) + { + fprintf(ci, "high"); + } + else + { + fprintf(ci, "normal"); + } + fclose(ci); + } +} diff --git a/common/ca_ci.h b/common/ca_ci.h index c4362f0..5a75650 100644 --- a/common/ca_ci.h +++ b/common/ca_ci.h @@ -194,8 +194,10 @@ typedef struct bool ccmgr_ready; + char ci_dev[32]; char name[512]; + bool newPids; bool newCapmt; bool multi; bool recordUse[CI_MAX_MULTI]; @@ -212,6 +214,8 @@ typedef struct CaIdVector cam_caids; std::priority_queue sendqueue; + std::vector pids; + bSIDVector bsids; unsigned char lastKey[32]; unsigned char scrambled; @@ -237,6 +241,38 @@ private: cCA(void); /// Private data for the CA module CS_CA_PDATA *privateData; + /// set inputs with tuner letter in tsmux + void setInputs(); + /// write ci info file to /tmp + void write_ci_info(int slot, CaIdVector caids); + /// delete ci info file + void del_ci_info(int slot); + /// extract audio / video pids from capmt + void extractPids(eDVBCISlot* slot); + /// ci module is detected + void ci_inserted(eDVBCISlot* slot); + /// ci module is removed + void ci_removed(eDVBCISlot* slot); + /// decode the tpdu tag + void process_tpdu(eDVBCISlot* slot, unsigned char tpdu_tag, __u8* data, int asn_data_length, int con_id); + /// set flag of running ci record to false + bool StopRecordCI( u64 TP, u16 SID, u8 source, u32 calen); + /// set flag of running ci live-tv to false + bool StopLiveCI( u64 TP, u16 SID, u8 source, u32 calen); + /// find an unused ci slot for use with service + SlotIt FindFreeSlot(u64 tpid, u8 source, u16 sid, ca_map_t camap, u8 scrambled); + /// get slot iterator by slot number + SlotIt GetSlot(unsigned int slot); + /// send buffered capmt to ci modul + bool SendCaPMT(eDVBCISlot* slot); + /// send a dummy capmt to ci for deactivating + bool SendNullPMT(eDVBCISlot* slot); + /// set ci source + void setSource(eDVBCISlot* slot); + /// set demux source + void setInputSource(eDVBCISlot* slot, bool ci); + /// check if data in queue + bool checkQueueSize(eDVBCISlot* slot); enum CA_INIT_MASK initMask; int num_slots; bool init; @@ -246,7 +282,9 @@ private: pthread_t slot_thread; public: + /// sh4 unused bool Init(void); + /// init ci and start the loop cCA(int Slots); /// Returns the number of CI slots uint32_t GetNumberCISlots(void); @@ -260,17 +298,23 @@ public: bool SendMessage(const CA_MESSAGE *Msg); /// Sets which modules to initialize. It is only /// possible to change this once! + /// sh4 unused void SetInitMask(enum CA_INIT_MASK InitMask); /// Sets the frequency (in Hz) of the TS stream input (only valid for CI) - void SetTSClock(u32 /*Speed*/) { return; }; + /// sh4 unused + void SetTSClock(u32 Speed); /// Start the CA module + /// sh4 unused bool Start(void); /// Stops the CA module + /// sh4 unused void Stop(void); /// Notify that the GUI is ready to receive messages /// (CA messages coming from a module) + /// sh4 unused void Ready(bool Set); /// Resets a module (if possible) + /// sh4 unused void ModuleReset(enum CA_SLOT_TYPE, uint32_t Slot); /// Checks if a module is present bool ModulePresent(enum CA_SLOT_TYPE, uint32_t Slot); @@ -285,29 +329,20 @@ public: /// Notify the module we closed the menu void MenuClose(enum CA_SLOT_TYPE, uint32_t Slot); /// Get the supported CAIDs -// int GetCAIDS(CaIdVector & /*Caids*/) { return 0; }; int GetCAIDS(CaIdVector &Caids); /// Send a CA-PMT object and Raw unparsed PMT to the CA layer bool SendCAPMT(u64 /*Source*/, u8 /*DemuxSource*/, u8 /*DemuxMask*/, const unsigned char * /*CAPMT*/, u32 /*CAPMTLen*/, const unsigned char * /*RawPMT*/, u32 /*RawPMTLen*/, enum CA_SLOT_TYPE SlotType = CA_SLOT_TYPE_ALL, unsigned char scrambled = 0, ca_map_t camap = std::set(), int mode = 0, bool enabled = false); - - bool StopRecordCI( u64 TP, u16 SID, u8 source, u32 calen); - bool StopLiveCI( u64 TP, u16 SID, u8 source, u32 calen); - SlotIt FindFreeSlot(u64 tpid, u8 source, u16 sid, ca_map_t camap, unsigned char scrambled); - SlotIt GetSlot(unsigned int slot); + /// sh4 unused bool SendDateTime(void); - bool SendCaPMT(eDVBCISlot* slot); + /// the main loop void slot_pollthread(void *c); - void setSource(eDVBCISlot* slot); - bool checkQueueSize(eDVBCISlot* slot); - void process_tpdu(eDVBCISlot* slot, unsigned char tpdu_tag, __u8* data, int asn_data_length, int con_id); - + /// check if current channel uses any ci module bool checkChannelID(u64 chanID); + /// set checking for live-tv use ci to true void setCheckLiveSlot(int check); - bool SendNullPMT(eDVBCISlot* slot); + /// as the name says bool CheckCerts(void); - void Test(int slot, CaIdVector caids); - void DelTest(int slot); /// Virtual destructor virtual ~cCA(); }; diff --git a/generic-pc/playback.cpp b/generic-pc/playback.cpp index 94ca12d..5e9c4ac 100644 --- a/generic-pc/playback.cpp +++ b/generic-pc/playback.cpp @@ -131,6 +131,11 @@ void cPlayback::SetTitle(int /*title*/) { } +uint64_t cPlayback::GetReadCount(void) +{ + return 0; +} + cPlayback::cPlayback(int /*num*/) { printf("%s:%s\n", FILENAME, __func__); diff --git a/libarmbox/cs_api.h b/libarmbox/cs_api.h index e4349dd..1532284 100644 --- a/libarmbox/cs_api.h +++ b/libarmbox/cs_api.h @@ -40,7 +40,7 @@ inline void cs_api_exit() #define cs_free_uncached free // Callback function helpers -static inline void cs_register_messenger(cs_messenger) { return; }; +void cs_register_messenger(cs_messenger messenger); static inline void cs_deregister_messenger(void) { return; }; //cs_messenger cs_get_messenger(void); diff --git a/libarmbox/hardware_caps.c b/libarmbox/hardware_caps.c index 8a19704..be7752d 100644 --- a/libarmbox/hardware_caps.c +++ b/libarmbox/hardware_caps.c @@ -29,7 +29,7 @@ hw_caps_t *get_hwcaps(void) memset(&caps, 0, sizeof(hw_caps_t)); initialized = 1; - caps.has_CI = 0; + caps.has_CI = 1; caps.can_cec = 1; caps.can_shutdown = 1; caps.display_xres = 16; diff --git a/libdvbci/descrambler.cpp b/libdvbci/descrambler.cpp index ca71db0..502ef1d 100644 --- a/libdvbci/descrambler.cpp +++ b/libdvbci/descrambler.cpp @@ -3,25 +3,106 @@ #include #include #include +#include +#include #include #include "misc.h" #include "descrambler.h" +#include + static const char * FILENAME = "[descrambler]"; -static const char *descrambler_filename = "/dev/dvb/adapter0/ca3"; static int desc_fd = -1; static int desc_user_count = 0; +#if HAVE_ARM_HARDWARE + +//static const char *descrambler_filename = "/dev/dvb/adapter0/ca0"; +//static const char *descrambler_filename = "/dev/dvb/adapter0/ca1"; +static const char *descrambler_filename = "/dev/ciplus_ca0"; + +enum ca_descr_data_type { + CA_DATA_IV, + CA_DATA_KEY, +}; + +enum ca_descr_parity { + CA_PARITY_EVEN, + CA_PARITY_ODD, +}; + +struct ca_descr_data { + unsigned int index; + enum ca_descr_parity parity; + enum ca_descr_data_type data_type; + unsigned int length; + unsigned char *data; +}; + +#define CA_SET_DESCR_DATA _IOW('o', 137, struct ca_descr_data) +//#define CA_SET_DESCR_DATA _IOW('o', 10, struct ca_descr_data) + +int descrambler_set_key(int index, int parity, unsigned char *data) +{ + struct ca_descr_data d; + int ret; + + printf("%s -> %s %s\n", FILENAME, __FUNCTION__, descrambler_filename); + + if (descrambler_open()) + { + printf("Complete Data-> Index: (%d) Parity: (%d) -> ", index, parity); + hexdump(data, 32); + + d.index = index; + d.parity = (ca_descr_parity)parity; + d.data_type = CA_DATA_KEY; + d.length = 16; + d.data = data; + + printf("AES Index: (%d) Parity: (%d) -> ", d.index, d.parity); + hexdump(d.data, 16); + + ret = ioctl(desc_fd, CA_SET_DESCR_DATA, &d); + if (ret) + { + printf("CA_SET_DESCR_DATA (AES) index=%d parity=%d (errno=%d %s)\n", index, parity, errno, strerror(errno)); + } + + d.index = index; + d.parity = (ca_descr_parity)parity; + d.data_type = CA_DATA_IV; + d.length = 16; + d.data = data + 16; + + printf("IV Index: (%d) Parity: (%d) -> ", d.index, d.parity); + hexdump(d.data, 16); + + ret = ioctl(desc_fd, CA_SET_DESCR_DATA, &d); + if (ret) + { + printf("CA_SET_DESCR_DATA (IV) index=%d parity=%d (errno=%d %s)\n", index, parity, errno, strerror(errno)); + } + + descrambler_close(); + } + return 0; +} + +#else + +static const char *descrambler_filename = "/dev/dvb/adapter0/ca3"; + /* Byte 0 to 15 are AES Key, Byte 16 to 31 are IV */ int descrambler_set_key(int index, int parity, unsigned char *data) { struct ca_descr_data d; - printf("%s -> %s\n", FILENAME, __FUNCTION__); + printf("%s -> %s %s\n", FILENAME, __FUNCTION__, descrambler_filename); index |= 0x100; @@ -32,37 +113,55 @@ int descrambler_set_key(int index, int parity, unsigned char *data) d.data_type = CA_DATA_KEY; d.length = 32; d.data = data; +#if 0 + printf("Index: %d Parity: (%d) -> ", d.index, d.parity); + hexdump(d.data, 32); +#endif + if (ioctl(desc_fd, CA_SET_DESCR_DATA, &d)) + { + printf("CA_SET_DESCR_DATA index=%d parity=%d (errno=%d %s)\n", index, parity, errno, strerror(errno)); + } printf("Index: %d Parity: (%d) -> ", d.index, d.parity); hexdump(d.data, 32); - if (ioctl(desc_fd, CA_SET_DESCR_DATA, &d)) - { - //printf("CA_SET_DESCR_DATA\n"); - } descrambler_close(); } return 0; } +#endif + +/* we don't use this for sh4 ci cam ! */ -/* we don't use this for ci cam ! */ -/* int descrambler_set_pid(int index, int enable, int pid) { struct ca_pid p; +#if HAVE_ARM_HARDWARE + unsigned int flags = 0x80; + + if (index) + flags |= 0x40; + if (enable) - p.index = index; - else - p.index = -1; + flags |= 0x20; + p.index = flags; p.pid = pid; +#else + p.index = index; + if (enable) + p.pid = pid; + else + p.pid = -1; +#endif - if (ioctl(desc_fd, CA_SET_PID, &p)) - printf("CA_SET_PID\n"); + printf("CA_SET_PID pid=0x%04x index=0x%04x\n", p.pid, p.index); + if (ioctl(desc_fd, CA_SET_PID, &p) == -1) + printf("CA_SET_PID pid=0x%04x index=0x%04x (errno=%d %s)\n", p.pid, p.index, errno, strerror(errno)); return 0; } -*/ + bool descrambler_open(void) { @@ -74,12 +173,6 @@ bool descrambler_open(void) return true; } -void descrambler_close(void) -{ - close(desc_fd); - desc_fd = -1; -} - int descrambler_init(void) { desc_user_count++; @@ -87,6 +180,12 @@ int descrambler_init(void) return 0; } +void descrambler_close(void) +{ + close(desc_fd); + desc_fd = -1; +} + void descrambler_deinit(void) { desc_user_count--; diff --git a/libdvbci/descrambler.h b/libdvbci/descrambler.h index 1e42aa9..e28391f 100644 --- a/libdvbci/descrambler.h +++ b/libdvbci/descrambler.h @@ -6,7 +6,7 @@ void descrambler_deinit(void); bool descrambler_open(void); void descrambler_close(void); int descrambler_set_key(int index, int parity, unsigned char *data); -/* we don't use this for ci cam ! */ -//int descrambler_set_pid(int index, int enable, int pid); +/* we don't use this for sh4 ci cam ! */ +int descrambler_set_pid(int index, int enable, int pid); #endif diff --git a/libdvbci/dvbci_ccmgr.cpp b/libdvbci/dvbci_ccmgr.cpp index 6dcbefe..3011d64 100644 --- a/libdvbci/dvbci_ccmgr.cpp +++ b/libdvbci/dvbci_ccmgr.cpp @@ -1347,6 +1347,38 @@ void eDVBCIContentControlManagerSession::resendKey(eDVBCISlot *tslot) */ if (!tslot->SidBlackListed && (tslot->recordUse[0] || tslot->liveUse[0])) + { +#if HAVE_ARM_HARDWARE + if (slot->newPids) + { + if (slot->pids.size()) + { + if (descrambler_open()) + { + for (unsigned int i = 0; i < slot->pids.size(); i++) + descrambler_set_pid((int)tslot->slot, 1, (int) slot->pids[i]); + descrambler_close(); + } + } + slot->newPids = false; + } + descrambler_set_key((int)tslot->slot, tslot->lastParity, tslot->lastKey); +#else + if (slot->newPids) + { + if (slot->pids.size()) + { + if (descrambler_open()) + { + for (unsigned int i = 0; i < slot->pids.size(); i++) + descrambler_set_pid((int)tslot->slot, 1, (int) slot->pids[i]); + descrambler_close(); + } + } + slot->newPids = false; + } descrambler_set_key((int)tslot->source, tslot->lastParity, tslot->lastKey); +#endif + } } diff --git a/libdvbci/dvbci_session.h b/libdvbci/dvbci_session.h index f1dd3c2..22b99c3 100644 --- a/libdvbci/dvbci_session.h +++ b/libdvbci/dvbci_session.h @@ -5,9 +5,9 @@ #define SLMS 256 -#define ROOT_CERT "/etc/pem/root.pem" -#define CUSTOMER_CERT "/etc/pem/customer.pem" -#define DEVICE_CERT "/etc/pem/device.pem" +#define ROOT_CERT "/etc/ssl/certs/root.pem" +#define CUSTOMER_CERT "/etc/ssl/certs/customer.pem" +#define DEVICE_CERT "/etc/ssl/certs/device.pem" class eDVBCISession { From b5820fadde47a80811ddf4167589cbfef0404a70 Mon Sep 17 00:00:00 2001 From: TangoCash Date: Sun, 5 Nov 2017 16:57:11 +0100 Subject: [PATCH 10/12] fix compile --- Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 4fd06a1..f523a79 100644 --- a/Makefile.am +++ b/Makefile.am @@ -56,5 +56,6 @@ if BOXTYPE_ARMBOX libstb_hal_test_LDADD += -lasound SUBDIRS += libarmbox libstb_hal_la_LIBADD += \ - libarmbox/libarmbox.la + libarmbox/libarmbox.la \ + libdvbci/libdvbci.la endif From cdbe0446274e977588f5a5a73c1b3c2ee679ecd0 Mon Sep 17 00:00:00 2001 From: TangoCash Date: Sun, 5 Nov 2017 16:58:19 +0100 Subject: [PATCH 11/12] fix compile #2 --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index f523a79..a7fb1ad 100644 --- a/Makefile.am +++ b/Makefile.am @@ -54,7 +54,7 @@ libstb_hal_la_LIBADD += \ endif if BOXTYPE_ARMBOX libstb_hal_test_LDADD += -lasound -SUBDIRS += libarmbox +SUBDIRS += libarmbox libdvbci libstb_hal_la_LIBADD += \ libarmbox/libarmbox.la \ libdvbci/libdvbci.la From a513b0bf3872c91dcbd6aa2f28810f27529d88c6 Mon Sep 17 00:00:00 2001 From: max_10 Date: Mon, 6 Nov 2017 00:03:40 +0100 Subject: [PATCH 12/12] ci: armbox fix cpu load --- common/ca_ci.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/common/ca_ci.cpp b/common/ca_ci.cpp index e4dc27d..c4a2b06 100644 --- a/common/ca_ci.cpp +++ b/common/ca_ci.cpp @@ -1346,6 +1346,9 @@ void cCA::slot_pollthread(void *c) while (1) { #if HAVE_ARM_HARDWARE /* Armbox */ + if (slot->init && !slot->mmiOpened) + sleep(1); + int len = 1024 *4; eData status;