diff --git a/data/locale/deutsch.locale b/data/locale/deutsch.locale index 540b9d65f..f875065b7 100644 --- a/data/locale/deutsch.locale +++ b/data/locale/deutsch.locale @@ -2291,6 +2291,7 @@ streaminfo.audiotype Audiotyp streaminfo.audiotype_unknown unbekannt streaminfo.average_bitrate Durchschnitt streaminfo.bitrate Bitrate +streaminfo.casystems Cryptsysteme streaminfo.framerate Bildrate streaminfo.framerate_unknown unbekannt streaminfo.head Tech. Information diff --git a/data/locale/english.locale b/data/locale/english.locale index e63350e96..3f5e038b3 100644 --- a/data/locale/english.locale +++ b/data/locale/english.locale @@ -2291,6 +2291,7 @@ streaminfo.audiotype Audiotype streaminfo.audiotype_unknown unknown streaminfo.average_bitrate Average streaminfo.bitrate Bitrate +streaminfo.casystems Conditional access systems streaminfo.framerate Framerate streaminfo.framerate_unknown unknown streaminfo.head Stream-Information diff --git a/src/gui/streaminfo2.cpp b/src/gui/streaminfo2.cpp index f4f8fdcf7..85c6ad479 100644 --- a/src/gui/streaminfo2.cpp +++ b/src/gui/streaminfo2.cpp @@ -31,6 +31,13 @@ #include #include +extern "C" { +#include +#include +} + +#include + #include #include @@ -54,6 +61,7 @@ #include #include #include +#include extern cVideo * videoDecoder; extern cAudio * audioDecoder; @@ -102,6 +110,8 @@ CStreamInfo2::CStreamInfo2() : fader(g_settings.theme.menu_Content_alpha) box_h = 0; box_h2 = 0; dmxbuf = NULL; + probebuf = NULL; + probe_thread = 0; } CStreamInfo2::~CStreamInfo2 () @@ -110,6 +120,221 @@ CStreamInfo2::~CStreamInfo2 () ts_close(); } +/* based on ffmpeg-2.2.1/libavformat/utils.c:print_fps() */ +static std::string fps_str(double d) +{ + uint64_t v = lrintf(d * 100); + char buf[64]; + if (v % 100) + snprintf(buf, sizeof(buf), "%3.2f", d); + else if (v % (100 * 1000)) + snprintf(buf, sizeof(buf), "%1.0f", d); + else + snprintf(buf, sizeof(buf), "%1.0fk", d / 1000); + + return std::string(buf); +} + +/* based on ffmpeg-2.2.1/libavformat/utils.c:dump_stream_format() */ +void CStreamInfo2::analyzeStream(AVFormatContext *avfc, unsigned int idx) +{ + std::map _m; + streamdata.push_back(_m); + std::map &m = streamdata.back(); + + AVStream *st = avfc->streams[idx]; + + m["language"] = " "; + AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL, 0); + if (lang) + m["language"] = getISO639Description(lang->value); + else { + lang = av_dict_get(st->metadata, "lang", NULL, 0); + if (lang) + m["language"] = getISO639Description(lang->value); + } + + char buf[256]; + avcodec_string(buf, sizeof(buf), st->codec, 0); + m["codec"] = buf; + size_t pos = m["codec"].find_first_of(":"); + if ( pos != std::string::npos) + m["codec"] = m["codec"].erase(0,pos+2); + m["codec_type"] = av_get_media_type_string(st->codec->codec_type); + m["codec_type"][0] ^= 'a' ^ 'A'; + + m["pid"] = to_string(st->id); + + if (st->sample_aspect_ratio.num && // default + av_cmp_q(st->sample_aspect_ratio, st->codec->sample_aspect_ratio)) { + AVRational display_aspect_ratio; + av_reduce(&display_aspect_ratio.num, &display_aspect_ratio.den, + st->codec->width * st->sample_aspect_ratio.num, + st->codec->height * st->sample_aspect_ratio.den, + 1024 * 1024); + snprintf(buf, sizeof(buf), "%d:%d", st->sample_aspect_ratio.num, st->sample_aspect_ratio.den); + m["sar"] = buf; + snprintf(buf, sizeof(buf), "%d:%d", display_aspect_ratio.num, display_aspect_ratio.den); + m["dar"] = buf; + } + if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { + if (st->avg_frame_rate.den && st->avg_frame_rate.num) + m["fps"] = fps_str(av_q2d(st->avg_frame_rate)); +#if FF_API_R_FRAME_RATE + if (st->r_frame_rate.den && st->r_frame_rate.num) + m["tbf"] = fps_str(av_q2d(st->r_frame_rate)); +#endif + if (st->time_base.den && st->time_base.num) + m["tbn"] = fps_str(1 / av_q2d(st->time_base)); + if (st->codec->time_base.den && st->codec->time_base.num) + m["tbc"] = fps_str(1 / av_q2d(st->codec->time_base)); + } + + m["disposition"] = ""; + if (st->disposition & AV_DISPOSITION_DEFAULT) + m["disposition"] += " (default)"; + if (st->disposition & AV_DISPOSITION_DUB) + m["disposition"] += " (dub)"; + if (st->disposition & AV_DISPOSITION_ORIGINAL) + m["disposition"] += " (original)"; + if (st->disposition & AV_DISPOSITION_COMMENT) + m["disposition"] += " (comment)"; + if (st->disposition & AV_DISPOSITION_LYRICS) + m["disposition"] += " (lyrics)"; + if (st->disposition & AV_DISPOSITION_KARAOKE) + m["disposition"] += " (karaoke)"; + if (st->disposition & AV_DISPOSITION_FORCED) + m["disposition"] += " (forced)"; + if (st->disposition & AV_DISPOSITION_HEARING_IMPAIRED) + m["disposition"] += " (hearing impaired)"; + if (st->disposition & AV_DISPOSITION_VISUAL_IMPAIRED) + m["disposition"] += " (visual impaired)"; + if (st->disposition & AV_DISPOSITION_CLEAN_EFFECTS) + m["disposition"] += " (clean effects)"; + if (!m["disposition"].empty()) + m["disposition"].erase(0, 1); + + //for (std::map::iterator it = m.begin(); it != m.end(); ++it) + // fprintf(stderr, "%s -> %s\n", it->first.c_str(), it->second.c_str()); +} + +void CStreamInfo2::analyzeStreams(AVFormatContext *avfc) +{ + // av_dump_format(avfc, 0, "", 0); + + streamdata.clear(); + for (unsigned int i = 0; i < avfc->nb_streams; i++) + analyzeStream(avfc, i); +} + +static cDemux * dmx = NULL; + +#define TS_LEN 188 +#define TS_BUF_SIZE (1024 * 1024 * 8 / TS_LEN * TS_LEN) + +static int read_packet(void *opaque, uint8_t *buf, int buf_size) +{ + CStreamInfo2 *me = (CStreamInfo2 *) opaque; + return me->readPacket(buf, buf_size); +} + +int CStreamInfo2::readPacket(uint8_t *buf, int buf_size) +{ + if (!probebuf) + return 0; + while (!abort_probing && (probebuf_length == probebuf_off) && (probebuf_off != probebuf_size)) + usleep(10000); + + if (!abort_probing) { + OpenThreads::ScopedLock lock(probe_mutex); + if (probebuf) { + int len = std::min(buf_size, (int)(probebuf_length - probebuf_off)); + memcpy(buf, probebuf + probebuf_off, len); + probebuf_off += len; + return len; + } + } + return -1; +} + +//#define ENABLE_FFMPEG_LOGGING +#ifdef ENABLE_FFMPEG_LOGGING +static void log_callback(void *, int, const char *format, va_list ap) +{ + vfprintf(stderr, format, ap); +} +#endif + +static int interrupt_cb(void *arg) +{ + CStreamInfo2 *me = (CStreamInfo2 *) arg; + return me->abort_probing; +} + +void CStreamInfo2::probeStreams() +{ + if (mp) { + AVFormatContext *avfc = mp->getPlayback()->GetAVFormatContext(); + if (avfc) { + analyzeStreams(avfc); + mp->getPlayback()->ReleaseAVFormatContext(); + } + probed = true; + } else { +#ifdef ENABLE_FFMPEG_LOGGING + av_log_set_callback(log_callback); +#endif + avcodec_register_all(); + av_register_all(); + + AVIOContext *avioc = NULL; + int buffer_size = 188 * 128; + unsigned char *buffer = (unsigned char *) av_malloc(buffer_size); + AVFormatContext *avfc = avformat_alloc_context(); + if (!avfc) { + av_freep(&buffer); + goto bye; + } + + avfc->interrupt_callback.callback = interrupt_cb; + avfc->interrupt_callback.opaque = (void *) this; + + avioc = avio_alloc_context (buffer, buffer_size, 0, this, read_packet, NULL, NULL); + if (!avioc) { + av_freep(&buffer); + avformat_free_context(avfc); + goto bye; + } + + avfc->pb = avioc; + avfc->flags |= AVFMT_FLAG_CUSTOM_IO; + avfc->probesize = probebuf_size/2; + + if (!avformat_open_input(&avfc, "", NULL, NULL)) { + avformat_find_stream_info(avfc, NULL); + analyzeStreams(avfc); + } + + avformat_close_input(&avfc); + avformat_free_context(avfc); + probed = true; +bye: + OpenThreads::ScopedLock lock(probe_mutex); + if(probebuf) { + delete [] probebuf; + probebuf = NULL; + } + } +} + +void *CStreamInfo2::probeStreams(void *arg) +{ + set_threadname(__func__); + CStreamInfo2 *me = (CStreamInfo2 *) arg; + me->probeStreams(); + pthread_exit(NULL); +} + int CStreamInfo2::exec (CMenuTarget * parent, const std::string &) { @@ -124,7 +349,7 @@ int CStreamInfo2::exec (CMenuTarget * parent, const std::string &) if (!mp->Playing()) mp = NULL; - frontend = CFEManager::getInstance()->getLiveFE(); + frontend = mp ? NULL : CFEManager::getInstance()->getLiveFE(); fader.StartFadeIn(); paint (paint_mode); @@ -144,61 +369,78 @@ int CStreamInfo2::doSignalStrengthLoop () neutrino_msg_t msg; neutrino_msg_t postmsg = 0; uint64_t maxb, minb, lastb, tmp_rate; - unsigned int current_pmt_version = (unsigned int)-1; + unsigned int current_pmt_version= pmt_version; int cnt = 0; + char tmp_str[150]; int delay_counter = 0; const int delay = 15; - int sw = g_Font[font_info]->getRenderWidth("99999"); + int sw = 3 * g_Font[font_small]->getRenderWidth(" ") + 8 * g_Font[font_small]->getMaxDigitWidth(); maxb = minb = lastb = tmp_rate = 0; - std::string br_str = std::string(g_Locale->getText(LOCALE_STREAMINFO_BITRATE)) + ":"; - std::string avg_str = "(" + std::string(g_Locale->getText(LOCALE_STREAMINFO_AVERAGE_BITRATE)) + ")"; - int offset = g_Font[font_info]->getRenderWidth(avg_str); - int dheight = g_Font[font_info]->getHeight (); - int dx1 = x + 10; + bool repaint_bitrate = true; ts_setup (); + frameBuffer->blit(); while (1) { + neutrino_msg_data_t data; + + uint64_t timeoutEnd = CRCInput::calcTimeoutEnd_MS(10); + g_RCInput->getMsgAbsoluteTimeout (&msg, &data, &timeoutEnd); + if (!mp) { - signal.sig = frontend->getSignalStrength() & 0xFFFF; - signal.snr = frontend->getSignalNoiseRatio() & 0xFFFF; - signal.ber = frontend->getBitErrorRate(); + signal.sig = 100 * (frontend->getSignalStrength() & 0xFFFF) >> 16; + signal.snr = 100 * (frontend->getSignalNoiseRatio() & 0xFFFF) >> 16; + signal.ber = 100 * (frontend->getBitErrorRate() & 0xFFFF) >> 16; // FIXME? + } + + bool got_rate = update_rate(); + + if (got_rate && (lastb != bit_s)) { + if (maxb < bit_s) + rate.max_short_average = maxb = bit_s; + if ((cnt > 10) && ((minb == 0) || (minb > bit_s))) + rate.min_short_average = minb = bit_s; } - int ret = update_rate (); if (paint_mode == 0) { - if (cnt < 12) cnt++; + int dx1 = x + 10; - if (ret && (lastb != bit_s)) { - lastb = bit_s; - - if (maxb < bit_s) - rate.max_short_average = maxb = bit_s; - if ((cnt > 10) && ((minb == 0) || (minb > bit_s))) - rate.min_short_average = minb = bit_s; - - char currate[150]; - sprintf(currate, "%u", rate.short_average / 1000); - g_Font[font_info]->RenderString(dx1, average_bitrate_pos, width/2, br_str, COL_MENUCONTENT_TEXT); - g_Font[font_info]->RenderString(dx1+average_bitrate_offset+sw+10 , average_bitrate_pos, offset, avg_str, COL_MENUCONTENT_TEXT); - frameBuffer->paintBoxRel (dx1 + average_bitrate_offset , average_bitrate_pos -dheight, sw, dheight, COL_MENUCONTENT_PLUS_0); - g_Font[font_info]->RenderString(dx1+average_bitrate_offset, average_bitrate_pos, sw, currate, COL_MENUCONTENT_TEXT); - } - if (!mp) { - showSNR (); - if (++delay_counter > delay) { - CZapitChannel * channel = CZapit::getInstance()->GetCurrentChannel(); - if (channel) - pmt_version = channel->getPmtVersion(); - delay_counter = 0; - if (pmt_version != current_pmt_version && delay_counter > delay){ - current_pmt_version = pmt_version; - paint_techinfo(dx1, y + hheight + 5); - } + if (got_rate && (rate.short_average || lastb) && (lastb != bit_s)) { + if (repaint_bitrate) { + snprintf(tmp_str, sizeof(tmp_str), "%s:",g_Locale->getText(LOCALE_STREAMINFO_BITRATE)); + g_Font[font_info]->RenderString(dx1, average_bitrate_pos, spaceoffset, tmp_str, COL_MENUCONTENT_TEXT); + snprintf(tmp_str, sizeof(tmp_str), " (%s)",g_Locale->getText(LOCALE_STREAMINFO_AVERAGE_BITRATE)); + g_Font[font_info]->RenderString(dx1 + spaceoffset + sw , average_bitrate_pos, box_width - spaceoffset - sw, tmp_str, COL_MENUCONTENT_TEXT); + repaint_bitrate = false; } + + frameBuffer->paintBoxRel (dx1 + spaceoffset, average_bitrate_pos - iheight, sw, iheight, COL_MENUCONTENT_PLUS_0); + char currate[140]; + snprintf(currate, sizeof(currate), "%10u", rate.short_average); + currate[0] = currate[2]; + currate[1] = currate[3]; + currate[2] = ' '; + currate[3] = currate[4]; + currate[4] = currate[5]; + currate[5] = currate[6]; + currate[6] = ' '; + g_Font[font_info]->RenderString (dx1 + spaceoffset, average_bitrate_pos, sw, currate, COL_MENUCONTENT_TEXT); + lastb = bit_s; } + if((!mp && pmt_version != current_pmt_version && delay_counter > delay) || probed){ + probed = false; + current_pmt_version = pmt_version; + paint_techinfo(techinfo_xpos, techinfo_ypos); + repaint_bitrate = true; + continue; + } + if (!mp) + showSNR (); + + delay_counter++; } rate.short_average = abit_s; + if (signal.max_ber < signal.ber) signal.max_ber = signal.ber; @@ -217,14 +459,13 @@ int CStreamInfo2::doSignalStrengthLoop () if ((signal.min_snr == 0) || (signal.min_snr > signal.snr)) signal.min_snr = signal.snr; + if (got_rate) { paint_signal_fe(rate, signal); - signal.old_sig = signal.sig; signal.old_snr = signal.snr; signal.old_ber = signal.ber; + } - neutrino_msg_data_t data; - /* rate limiting is done in update_rate */ g_RCInput->getMsg_us(&msg, &data, 0); if ((msg == NeutrinoMessages::EVT_TIMER) && (data == fader.GetFadeTimer())) @@ -253,9 +494,10 @@ int CStreamInfo2::doSignalStrengthLoop () hide (); paint_mode = !paint_mode; paint (paint_mode); + repaint_bitrate = true; continue; } - else if(msg == CRCInput::RC_setup) { + else if(msg == CRCInput::RC_setup || msg == CRCInput::RC_home) { res = menu_return::RETURN_EXIT_ALL; fadeout = true; } @@ -276,6 +518,7 @@ int CStreamInfo2::doSignalStrengthLoop () // -- push other events if (msg > CRCInput::RC_MaxRC && msg != CRCInput::RC_timeout) CNeutrinoApp::getInstance ()->handleMsg (msg, data); + frameBuffer->blit(); } delete signalbox; signalbox = NULL; @@ -293,13 +536,11 @@ void CStreamInfo2::hide () { pip->hide(); frameBuffer->paintBackgroundBoxRel (0, 0, max_width, max_height); + frameBuffer->blit(); } void CStreamInfo2::paint_signal_fe_box(int _x, int _y, int w, int h) { - int y1; - int xd = w/4; - std::string tname(g_Locale->getText(LOCALE_STREAMINFO_SIGNAL)); tname += ": "; if (mp) @@ -312,12 +553,6 @@ void CStreamInfo2::paint_signal_fe_box(int _x, int _y, int w, int h) else tname += to_string(1 + frontend->getNumber()) + ": " + frontend->getName(); -#if 0 - int tuner = 1 + frontend->getNumber(); - char tname[255]; - snprintf(tname, sizeof(tname), "%s: %d: %s", g_Locale->getText(LOCALE_STREAMINFO_SIGNAL), tuner, frontend->getName()); -#endif - g_Font[font_small]->RenderString(_x, _y+iheight+15, width-_x-10, tname /*tuner_name.c_str()*/, COL_MENUCONTENT_TEXT); sigBox_x = _x; @@ -326,41 +561,45 @@ void CStreamInfo2::paint_signal_fe_box(int _x, int _y, int w, int h) sigBox_h = h-iheight*3; frameBuffer->paintBoxRel(sigBox_x,sigBox_y,sigBox_w+2,sigBox_h, COL_BLACK); sig_text_y = sigBox_y + sigBox_h; - y1 = sig_text_y + sheight+4; + + int y1 = sig_text_y + sheight+4; int fw = g_Font[font_small]->getWidth(); - - if (!mp) { - frameBuffer->paintBoxRel(_x+xd*0,y1- 12,16,2, COL_RED); //red - g_Font[font_small]->RenderString(_x+20+xd*0, y1, fw*4, "BER", COL_MENUCONTENT_TEXT); - - frameBuffer->paintBoxRel(_x+xd*1,y1- 12,16,2,COL_BLUE); //blue - g_Font[font_small]->RenderString(_x+20+xd*1, y1, fw*4, "SNR", COL_MENUCONTENT_TEXT); - - frameBuffer->paintBoxRel(_x+8+xd*2,y1- 12,16,2, COL_GREEN); //green - g_Font[font_small]->RenderString(_x+28+xd*2, y1, fw*4, "SIG", COL_MENUCONTENT_TEXT); - } - - frameBuffer->paintBoxRel(_x+xd*3,y1- 12,16,2,COL_YELLOW); // near yellow - g_Font[font_small]->RenderString(_x+20+xd*3, y1, fw*5, "Bitrate", COL_MENUCONTENT_TEXT); - - sig_text_ber_x = _x + xd * 0; - sig_text_snr_x = _x + 5 + xd * 1; - sig_text_sig_x = _x + 5 + xd * 2; - sig_text_rate_x = _x + 10 + xd * 3; - int maxmin_x; // x-position of min and max int fontW = g_Font[font_small]->getWidth(); + int xd; + int col = 0; - if (paint_mode == 0) - maxmin_x = sig_text_ber_x-(fontW*4); - else - maxmin_x = _x + 40 + xd * 3 + (fontW*4); + if (paint_mode == 0) { + maxmin_x = _x; + xd = (w - 5 * fontW)/4; + _x += 5 * fontW; + } else { + maxmin_x = _x + 40; + xd = (w - 5 * fontW + 40)/5; + col = 1; + } - g_Font[font_small]->RenderString(maxmin_x, y1 + sheight + 5, fw*3, "max", COL_MENUCONTENT_TEXT); + g_Font[font_small]->RenderString(maxmin_x, y1 + (sheight + 1) +5, fw*3, "max", COL_MENUCONTENT_TEXT); g_Font[font_small]->RenderString(maxmin_x, y1 + (sheight * 2) +5, fw*3, "now", COL_MENUCONTENT_TEXT); g_Font[font_small]->RenderString(maxmin_x, y1 + (sheight * 3) +5, fw*3, "min", COL_MENUCONTENT_TEXT); + if (!mp) { + g_Font[font_small]->RenderString(_x+xd*col, y1, fw*8, "BER [%]", COL_RED); + sig_text_ber_x = _x + 5 + xd * col; + col++; + + g_Font[font_small]->RenderString(_x+xd*col, y1, fw*8, "SNR [%]", COL_LIGHT_BLUE); + sig_text_snr_x = _x + 5 + xd * col; + col++; + + g_Font[font_small]->RenderString(_x+xd*col, y1, fw*8, "SIG [%]", COL_GREEN); + sig_text_sig_x = _x + 5 + xd * col; + col++; + } + + g_Font[font_small]->RenderString(_x+xd*col, y1, fw*10, "BR [kbps]", COL_YELLOW); + sig_text_rate_x = _x + 5 + xd * col; sigBox_pos = 0; @@ -406,26 +645,24 @@ void CStreamInfo2::paint_signal_fe(struct bitrate br, struct feSignal s) SignalRenderStr(s.max_ber, sig_text_ber_x, yt); SignalRenderStr(s.min_ber, sig_text_ber_x, yt + (sheight * 2)); } - yd = y_signal_fe (s.ber, 4000, sigBox_h); - frameBuffer->paintPixel(sigBox_x+x_now, sigBox_y+sigBox_h-yd, COL_RED); //red - + yd = y_signal_fe (s.ber, 100, sigBox_h); + frameBuffer->paintPixel(sigBox_x+x_now, sigBox_y+sigBox_h-yd, COL_RED); if (s.sig != s.old_sig) { SignalRenderStr(s.sig, sig_text_sig_x, yt + sheight); SignalRenderStr(s.max_sig, sig_text_sig_x, yt); SignalRenderStr(s.min_sig, sig_text_sig_x, yt + (sheight * 2)); } - yd = y_signal_fe (s.sig, 65000, sigBox_h); - frameBuffer->paintPixel(sigBox_x+x_now, sigBox_y+sigBox_h-yd, COL_GREEN); //green - + yd = y_signal_fe (s.sig, 100, sigBox_h); + frameBuffer->paintPixel(sigBox_x+x_now, sigBox_y+sigBox_h-yd, COL_GREEN); if (s.snr != s.old_snr) { SignalRenderStr(s.snr, sig_text_snr_x, yt + sheight); SignalRenderStr(s.max_snr, sig_text_snr_x, yt); SignalRenderStr(s.min_snr, sig_text_snr_x, yt + (sheight * 2)); } - yd = y_signal_fe (s.snr, 65000, sigBox_h); - frameBuffer->paintPixel(sigBox_x+x_now, sigBox_y+sigBox_h-yd, COL_BLUE); //blue + yd = y_signal_fe (s.snr, 100, sigBox_h); + frameBuffer->paintPixel(sigBox_x+x_now, sigBox_y+sigBox_h-yd, COL_LIGHT_BLUE); } } @@ -473,13 +710,6 @@ void CStreamInfo2::paint (int /*mode*/) int xpos = x + 10; if (paint_mode == 0) { - if (signalbox != NULL) - { - signalbox->kill(); - delete signalbox; - signalbox = NULL; - } - // -- tech Infos, PIG, small signal graph head_string = g_Locale->getText (LOCALE_STREAMINFO_HEAD); CVFD::getInstance ()->setMode (CVFD::MODE_MENU_UTF8, head_string); @@ -493,9 +723,15 @@ void CStreamInfo2::paint (int /*mode*/) pip = new CComponentsPIP(width-width/3-10, y+10, 33); pip->paint(CC_SAVE_SCREEN_NO); + techinfo_xpos = xpos; + techinfo_ypos = ypos; + paint_techinfo (xpos, ypos); - paint_signal_fe_box (width - width/3 - 10, y + 10 + height/3, width/3, height/3 + hheight); + paint_signal_fe_box (width - width/3 - 10, (y + 10 + height/3 + hheight), width/3, height/3 + hheight); } else { + delete signalbox; + signalbox = NULL; + // -- small PIG, small signal graph // -- paint backround, title pig, etc. frameBuffer->paintBoxRel (0, 0, max_width, max_height, COL_MENUCONTENT_PLUS_0); @@ -505,14 +741,23 @@ void CStreamInfo2::paint (int /*mode*/) } } +struct row { + std::string key; + std::string val; + Font *f; + int col; + row(): f(g_Font[SNeutrinoSettings::FONT_TYPE_MENU]) + { + } +}; + void CStreamInfo2::paint_techinfo(int xpos, int ypos) { char buf[100]; - int xres = 0, yres = 0, aspectRatio = 0, framerate = -1; + int xres = 0, yres = 0, aspectRatio = 0, framerate = -1, i = 0; // paint labels - int spaceoffset = 0,i = 0; int ypos1 = ypos; - int box_width = width-width/3-10; + box_width = width*2/3 - 10 - xpos; yypos = ypos; if(box_h > 0) @@ -522,352 +767,334 @@ void CStreamInfo2::paint_techinfo(int xpos, int ypos) if(!channel) return; - int array[]= {g_Font[font_info]->getRenderWidth(g_Locale->getText (LOCALE_STREAMINFO_RESOLUTION)), - g_Font[font_info]->getRenderWidth(g_Locale->getText (LOCALE_STREAMINFO_VIDEOSYSTEM)), - g_Font[font_info]->getRenderWidth(g_Locale->getText (LOCALE_STREAMINFO_OSD_RESOLUTION)), - g_Font[font_info]->getRenderWidth(g_Locale->getText (LOCALE_STREAMINFO_ARATIO)), - g_Font[font_info]->getRenderWidth(g_Locale->getText (LOCALE_STREAMINFO_BITRATE)), - g_Font[font_info]->getRenderWidth(g_Locale->getText (LOCALE_STREAMINFO_FRAMERATE)), - g_Font[font_info]->getRenderWidth(g_Locale->getText (LOCALE_STREAMINFO_AUDIOTYPE)), - g_Font[font_info]->getRenderWidth(g_Locale->getText (LOCALE_SCANTS_FREQDATA))}; + ypos += iheight; + + std::vector v; + row r; + + if (mp) { + if (CNeutrinoApp::getInstance()->getMode() == NeutrinoMessages::mode_webtv) { + // url + r.key = "URL"; + r.val = channel->getUrl(); + } else { + // file + r.key = g_Locale->getText (LOCALE_MOVIEBROWSER_INFO_FILE); + r.val = mp->GetFile(); + } + r.key += ": "; + r.col = COL_MENUCONTENT_TEXT; + v.push_back(r); + + //provider + if ((CNeutrinoApp::getInstance()->getMode() == NeutrinoMessages::mode_webtv) && (channel->pname)) { + std::string prov_name = channel->pname; + prov_name.erase( std::remove(prov_name.begin(), prov_name.end(), '['), prov_name.end() ); + prov_name.erase( std::remove(prov_name.begin(), prov_name.end(), ']'), prov_name.end() ); + r.key = g_Locale->getText (LOCALE_CHANNELLIST_PROVS); + r.key += ": "; + r.val = prov_name.c_str(); + r.col = COL_MENUCONTENT_TEXT; + v.push_back(r); + } + + scaling = 8000; + + } else { + // channel + r.key = g_Locale->getText (LOCALE_TIMERLIST_CHANNEL); + r.key += ": "; + r.val = channel->getName().c_str(); + r.col = COL_MENUCONTENT_TEXT; + v.push_back(r); + + //provider + if(channel->pname){ + std::string prov_name = channel->pname; + size_t pos = prov_name.find_first_of("]"); + if((pos != std::string::npos) && (pos+2 < prov_name.length())) + prov_name=prov_name.substr(pos+2); + r.key = g_Locale->getText (LOCALE_CHANNELLIST_PROVS); + r.key += ": "; + r.val = prov_name.c_str(); + r.col = COL_MENUCONTENT_TEXT; + v.push_back(r); + } + + transponder t; + t = *frontend->getParameters(); + + if (CFrontend::isSat(t.feparams.delsys)) + r.key = g_Locale->getText (LOCALE_SATSETUP_SATELLITE); + else if (CFrontend::isCable(t.feparams.delsys)) + r.key = g_Locale->getText (LOCALE_CHANNELLIST_PROVS); + else if (CFrontend::isTerr(t.feparams.delsys)) + r.key = g_Locale->getText (LOCALE_TERRESTRIALSETUP_AREA); + + r.key += ": "; + r.val = CServiceManager::getInstance()->GetSatelliteName(channel->getSatellitePosition()).c_str(); + r.col = COL_MENUCONTENT_TEXT; + v.push_back(r); + + // ts frequency + scaling = 27000; + if (CFrontend::isSat(t.feparams.delsys) && t.feparams.delsys == DVB_S) + scaling = 15000; + r.key = g_Locale->getText (LOCALE_SCANTS_FREQDATA); + r.val = t.description(); + r.col = COL_MENUCONTENT_TEXT; + v.push_back(r); + + r.key = r.val = ""; + v.push_back(r); + + // video pid + if ( g_RemoteControl->current_PIDs.PIDs.vpid){ + r.key = "Vpid: "; + i = g_RemoteControl->current_PIDs.PIDs.vpid; + snprintf(buf, sizeof(buf), "0x%04X (%i)", i, i); + r.val = buf; + r.col = COL_MENUCONTENT_TEXT; + v.push_back(r); + } - for(i=0 ; i<(int)(sizeof(array)/sizeof(array[0])); i++) { - if(spaceoffset < array[i]) - spaceoffset = array[i]; } - spaceoffset += g_Font[font_info]->getRenderWidth(" "); - - average_bitrate_offset = spaceoffset; - int box_width2 = box_width-(spaceoffset+xpos); - - if((channel->getVideoPid() || (IS_WEBCHAN(channel->getChannelID()) && CNeutrinoApp::getInstance()->getMode() == NeutrinoMessages::mode_webtv)) && !(videoDecoder->getBlank())){ +#if BOXMODEL_UFS910 + if(mp || channel->getVideoPid()) { +#else + if(((mp && IS_WEBCHAN(channel->getChannelID()) && CNeutrinoApp::getInstance()->getMode() == NeutrinoMessages::mode_webtv) || channel->getVideoPid()) && !(videoDecoder->getBlank())) { +#endif videoDecoder->getPictureInfo(xres, yres, framerate); if (yres == 1088) yres = 1080; aspectRatio = videoDecoder->getAspectRatio(); } - //Video RESOLUTION - ypos += iheight; - snprintf(buf, sizeof(buf), "%s:",g_Locale->getText (LOCALE_STREAMINFO_RESOLUTION)); - g_Font[font_info]->RenderString (xpos, ypos, box_width, buf, COL_MENUCONTENT_TEXT); - snprintf(buf, sizeof(buf), "%dx%d", xres, yres); - g_Font[font_info]->RenderString (xpos+spaceoffset, ypos, box_width2, buf, COL_MENUCONTENT_TEXT); + // video resolution + r.key = g_Locale->getText (LOCALE_STREAMINFO_RESOLUTION); + r.key += ": "; + snprintf (buf, sizeof(buf), "%dx%d", xres, yres); + r.val = buf; + r.col = COL_MENUCONTENT_TEXT; + v.push_back(r); -#if HAVE_COOL_HARDWARE - //Video SYSTEM - ypos += iheight; - snprintf(buf, sizeof(buf), "%s:", g_Locale->getText (LOCALE_STREAMINFO_VIDEOSYSTEM)); - g_Font[font_info]->RenderString (xpos, ypos, box_width, buf, COL_MENUCONTENT_TEXT); - cs_vs_format_t vsfn; - videoDecoder->GetVideoSystemFormatName(&vsfn); -#ifdef BOXMODEL_CS_HD1 - snprintf(buf, sizeof(buf), "HDMI: %s%s", vsfn.format, -#else - snprintf(buf, sizeof(buf), "HDMI: %s, Scart/Cinch: %s%s", vsfn.formatHD, vsfn.formatSD, -#endif - (g_settings.video_Mode == VIDEO_STD_AUTO)?" (AUTO)":""); - g_Font[font_info]->RenderString (xpos+spaceoffset, ypos, box_width2, buf, COL_MENUCONTENT_TEXT); -#endif - - //OSD RESOLUTION - ypos += iheight; - snprintf(buf, sizeof(buf), "%s:",g_Locale->getText (LOCALE_STREAMINFO_OSD_RESOLUTION)); - g_Font[font_info]->RenderString (xpos, ypos, box_width, buf, COL_MENUCONTENT_TEXT); - snprintf(buf, sizeof(buf), "%dx%d", frameBuffer->getScreenWidth(true), frameBuffer->getScreenHeight(true)); - g_Font[font_info]->RenderString (xpos+spaceoffset, ypos, box_width2, buf, COL_MENUCONTENT_TEXT); - - //Aspect Ratio - ypos += iheight; - snprintf(buf, sizeof(buf), "%s:",g_Locale->getText (LOCALE_STREAMINFO_ARATIO)); - g_Font[font_info]->RenderString (xpos, ypos, box_width, buf, COL_MENUCONTENT_TEXT); - switch (aspectRatio) { - case 0: - snprintf(buf, sizeof(buf), "N/A"); - break; - case 1: - snprintf(buf, sizeof(buf), "4:3"); - break; - case 2: - snprintf(buf, sizeof(buf), "14:9"); - break; - case 3: - snprintf(buf, sizeof(buf), "16:9"); - break; - case 4: - snprintf(buf, sizeof(buf), "20:9"); - break; - default: - strncpy (buf, g_Locale->getText (LOCALE_STREAMINFO_ARATIO_UNKNOWN), sizeof (buf)-1); + std::string tmp_fps = ""; + std::string tmp_ar = ""; + for (std::vector >::iterator it = streamdata.begin(); it != streamdata.end(); ++it) + if ((*it)["codec_type"].substr(0,5) == "Video") { + tmp_ar = (*it)["dar"]; + if (!tmp_ar.empty()) + tmp_ar += " / "; + tmp_ar += (*it)["sar"]; + tmp_fps = (*it)["fps"]; } - g_Font[font_info]->RenderString (xpos+spaceoffset, ypos, box_width2, buf, COL_MENUCONTENT_TEXT); - //Video FRAMERATE - ypos += iheight; - snprintf(buf, sizeof(buf), "%s:", g_Locale->getText (LOCALE_STREAMINFO_FRAMERATE)); - g_Font[font_info]->RenderString (xpos, ypos, box_width, buf, COL_MENUCONTENT_TEXT); - switch (framerate) { - case 0: - snprintf (buf,sizeof(buf), "23.976fps"); - break; - case 1: - snprintf (buf,sizeof(buf), "24fps"); - break; - case 2: - snprintf (buf,sizeof(buf), "25fps"); - break; - case 3: - snprintf (buf,sizeof(buf), "29,976fps"); - break; - case 4: - snprintf (buf,sizeof(buf), "30fps"); - break; - case 5: - snprintf (buf,sizeof(buf), "50fps"); - break; - case 6: - snprintf (buf,sizeof(buf), "50,94fps"); - break; - case 7: - snprintf (buf,sizeof(buf), "60fps"); - break; - default: - strncpy (buf, g_Locale->getText (LOCALE_STREAMINFO_FRAMERATE_UNKNOWN), sizeof (buf)-1); - break; + // aspect ratio + r.key = g_Locale->getText (LOCALE_STREAMINFO_ARATIO); + r.key += ": "; + if (aspectRatio < 0 || aspectRatio > 4) { + r.val = tmp_ar; + if (r.val.empty()) + r.val = g_Locale->getText (LOCALE_STREAMINFO_ARATIO_UNKNOWN); + } else { + const char *arr[] = { "N/A", "4:3", "14:9", "16:9", "20:9" }; + r.val = arr[aspectRatio]; } - g_Font[font_info]->RenderString (xpos+spaceoffset, ypos, box_width2, buf, COL_MENUCONTENT_TEXT); + r.col = COL_MENUCONTENT_TEXT; + v.push_back(r); + + // video framerate + r.key = g_Locale->getText (LOCALE_STREAMINFO_FRAMERATE); + r.key += ": "; + if (framerate < 0 || framerate > 7) { + r.val = tmp_fps; + if (r.val.empty()) + r.val = g_Locale->getText (LOCALE_STREAMINFO_FRAMERATE_UNKNOWN); + else + r.val += "fps"; + } else { + const char *arr[] = { "23.976fps", "24fps", "25fps", "29,976fps", "30fps", "50fps", "50,94fps", "60fps" }; + r.val = arr[framerate]; + } + r.col = COL_MENUCONTENT_TEXT; + v.push_back(r); + // place for average bitrate - average_bitrate_pos = ypos += iheight; - //AUDIOTYPE - ypos += iheight; - - snprintf(buf, sizeof(buf), "%s:", g_Locale->getText (LOCALE_STREAMINFO_AUDIOTYPE)); - g_Font[font_info]->RenderString (xpos, ypos, box_width, buf, COL_MENUCONTENT_TEXT); - - int type = 0, layer = 0, freq = 0, mode = 0, lbitrate = 0; - /* - audioDecoder->getAudioInfo() seems broken in libcoolstream2. - ddmode is always 1 ("CH1/CH2"). - */ - audioDecoder->getAudioInfo(type, layer, freq, lbitrate, mode); - std::string desc = "N/A"; - if (!g_RemoteControl->current_PIDs.APIDs.empty()) - desc = g_RemoteControl->current_PIDs.APIDs[g_RemoteControl->current_PIDs.PIDs.selected_apid].desc; - - if (type == AUDIO_FMT_MPEG || type == AUDIO_FMT_MP3) - { - const char *mpegmodes[] = - { - "stereo", - "joint_st", - "dual_ch", - "single_ch" - }; - int max_mode = sizeof(mpegmodes) / sizeof(mpegmodes[0]); - snprintf(buf, sizeof(buf), "MPEG %s (%d) (%s)", - (mode > max_mode) ? "unk" : mpegmodes[mode], - freq, desc.c_str()); - } - else if (type == AUDIO_FMT_DOLBY_DIGITAL || type == AUDIO_FMT_DD_PLUS) - { - const char *ddmodes[] = - { - "CH1/CH2", - "C", - "L/R", - "L/C/R", - "L/R/S", - "L/C/R/S", - "L/R/SL/SR", - "L/C/R/SL/SR" - }; - int max_mode = sizeof(ddmodes) / sizeof(ddmodes[0]); - snprintf(buf, sizeof(buf), "%s %s (%d) (%s)", - (type == AUDIO_FMT_DOLBY_DIGITAL) ? "DD" : "DD+", - (mode > max_mode) ? "unk" : ddmodes[mode], - freq, desc.c_str()); - } - else if (type == AUDIO_FMT_AAC || type == AUDIO_FMT_AAC_PLUS) - { - const char *aacmodes[] = - { - "N/S", - "Mono", - "L/R", - "L/C/R", - "L/C/R/SR/SL", - "L/C/R/SR/SL/S", - "L/R/RL/RR", - "L/C/R/S", - "L/R/SL/SR", - "Dual-Mono" - }; - int max_mode = sizeof(aacmodes) / sizeof(aacmodes[0]); - snprintf(buf, sizeof(buf), "%s %s (%d) (%s)", - (type == AUDIO_FMT_AAC) ? "AAC" : "AAC+", - (mode > max_mode) ? "unk" : aacmodes[mode], - freq, desc.c_str()); - } - else - { - snprintf(buf, sizeof(buf), "%s (%d) (%s)", - g_Locale->getText(LOCALE_STREAMINFO_AUDIOTYPE_UNKNOWN), - freq, desc.c_str()); - } - g_Font[font_info]->RenderString (xpos+spaceoffset, ypos, box_width2, buf, COL_MENUCONTENT_TEXT); + average_bitrate_pos = ypos + iheight * v.size(); + r.key = r.val = ""; + v.push_back(r); if (mp) { - //channel - ypos += iheight; - if (CNeutrinoApp::getInstance()->getMode() == NeutrinoMessages::mode_webtv || CNeutrinoApp::getInstance()->getMode() == NeutrinoMessages::mode_webradio) { - snprintf(buf, sizeof(buf), "%s:",g_Locale->getText (LOCALE_TIMERLIST_CHANNEL));//swiped locale - g_Font[font_info]->RenderString(xpos, ypos, box_width, buf , COL_MENUCONTENT_TEXT); - snprintf(buf, sizeof(buf), "%s", channel->getName().c_str()); - g_Font[font_info]->RenderString (xpos+spaceoffset, ypos, box_width2, buf, COL_MENUCONTENT_TEXT); - } else { - snprintf(buf, sizeof(buf), "%s:",g_Locale->getText (LOCALE_MOVIEBROWSER_INFO_FILE));//swiped locale - g_Font[font_info]->RenderString(xpos, ypos, box_width, buf , COL_MENUCONTENT_TEXT); - snprintf(buf, sizeof(buf), "%s", mp->GetFile().c_str()); - g_Font[font_info]->RenderString (xpos+spaceoffset, ypos, box_width2, buf, COL_MENUCONTENT_TEXT); + std::string details(" "); + for (std::vector >::iterator it = streamdata.begin(); it != streamdata.end(); ++it) + if ((*it)["codec_type"].substr(0,5) == "Video") { + details = (*it)["language"]; + if (details != " ") + details += ", "; + details += (*it)["codec"]; + if (details == " ") + details.clear(); + r.key = (*it)["codec_type"]; + r.key += ": "; + r.val = details.c_str(); + r.col = COL_MENUCONTENT_TEXT; + v.push_back(r); + } + } + + // audio + r.key = g_Locale->getText (LOCALE_STREAMINFO_AUDIOTYPE); + r.key += ": "; + std::string desc = "N/A"; + if (!mp && !g_RemoteControl->current_PIDs.APIDs.empty()) + desc = g_RemoteControl->current_PIDs.APIDs[g_RemoteControl->current_PIDs.PIDs.selected_apid].desc; + r.val = mp ? mp->getAPIDDesc(mp->getAPID()).c_str() : desc.c_str(); + r.col = COL_MENUCONTENT_TEXT; + v.push_back(r); + + if (mp) { + std::string details(" "); + for (std::vector >::iterator it = streamdata.begin(); it != streamdata.end(); ++it) + if ((*it)["codec_type"].substr(0,5) == "Audio") { + details = (*it)["language"]; + if (details != " ") + details += ", "; + details += (*it)["codec"]; + if (details == " ") + details.clear(); + r.key = (*it)["codec_type"]; + r.key += ": "; + r.val = details.c_str(); + r.col = COL_MENUCONTENT_TEXT; + v.push_back(r); + } + + r.key = r.val = ""; + v.push_back(r); + + // picon + if (CNeutrinoApp::getInstance()->getMode() == NeutrinoMessages::mode_webtv) { + r.key = "Picon"; + r.key += ": "; + snprintf(buf, sizeof(buf), "%llx.png", channel->getChannelID() & 0xFFFFFFFFFFFFULL); + r.val = buf; + r.col = COL_MENUCONTENT_TEXT; + v.push_back(r); } - // paint labels - int fontW = g_Font[font_small]->getWidth(); - spaceoffset = 7 * fontW; - box_width2 = box_width-(spaceoffset+xpos); - - //channellogo - ypos+= sheight; - sprintf(buf, "%llx.png", channel->getChannelID() & 0xFFFFFFFFFFFFULL); - g_Font[font_small]->RenderString(xpos, ypos, box_width, "Logo:" , COL_INFOBAR_TEXT); - g_Font[font_small]->RenderString(xpos+spaceoffset, ypos, box_width2, buf, COL_INFOBAR_TEXT); - - scaling = 27000; - } else { - - transponder t; - t = *frontend->getParameters(); - //satellite - ypos += iheight; - if (CFrontend::isSat(t.feparams.delsys)) - snprintf(buf, sizeof(buf), "%s:",g_Locale->getText (LOCALE_SATSETUP_SATELLITE));//swiped locale - else if (CFrontend::isCable(t.feparams.delsys)) - snprintf(buf, sizeof(buf), "%s:",g_Locale->getText (LOCALE_CHANNELLIST_PROVS)); - else if (CFrontend::isTerr(t.feparams.delsys)) - snprintf(buf, sizeof(buf), "%s:",g_Locale->getText (LOCALE_TERRESTRIALSETUP_AREA)); - - g_Font[font_info]->RenderString(xpos, ypos, box_width, buf, COL_MENUCONTENT_TEXT); - - // TODO: split info WebTV/WebRadio - snprintf(buf, sizeof(buf), "%s", IS_WEBCHAN(channel->getChannelID()) ? "Web-Channel" : - CServiceManager::getInstance()->GetSatelliteName(channel->getSatellitePosition()).c_str()); - g_Font[font_info]->RenderString (xpos+spaceoffset, ypos, box_width2, buf, COL_MENUCONTENT_TEXT); - - //channel - ypos += iheight; - snprintf(buf, sizeof(buf), "%s:",g_Locale->getText (LOCALE_TIMERLIST_CHANNEL));//swiped locale - g_Font[font_info]->RenderString(xpos, ypos, box_width, buf , COL_MENUCONTENT_TEXT); - // process additional RealName if UserName exists >> uname.empty() ? realname : uname + realname - snprintf(buf, sizeof(buf), "%s", (channel->getName()==channel->getRealname()) ? channel->getRealname().c_str():(channel->getName()+" << "+channel->getRealname()).c_str()); - g_Font[font_info]->RenderString (xpos+spaceoffset, ypos, box_width2, buf, COL_MENUCONTENT_TEXT); - - //tsfrequenz - ypos += iheight; - - scaling = 27000; - if (CFrontend::isSat(t.feparams.delsys) && t.feparams.delsys == DVB_S) - scaling = 15000; - - snprintf(buf, sizeof(buf), "%s",g_Locale->getText (LOCALE_SCANTS_FREQDATA)); - g_Font[font_info]->RenderString(xpos, ypos, box_width, buf , COL_MENUCONTENT_TEXT); - g_Font[font_info]->RenderString(xpos+spaceoffset, ypos, box_width2, t.description().c_str(), COL_MENUCONTENT_TEXT); - - // paint labels - int fontW = g_Font[font_small]->getWidth(); - spaceoffset = 7 * fontW; - box_width2 = box_width-(spaceoffset+xpos); - - //onid - ypos+= sheight; - snprintf(buf, sizeof(buf), "0x%04X (%i)", channel->getOriginalNetworkId(), channel->getOriginalNetworkId()); - g_Font[font_small]->RenderString(xpos, ypos, box_width, "ONid:" , COL_MENUCONTENT_TEXT); - g_Font[font_small]->RenderString(xpos+spaceoffset, ypos, box_width2, buf, COL_MENUCONTENT_TEXT); - - //sid - ypos+= sheight; - snprintf(buf, sizeof(buf), "0x%04X (%i)", channel->getServiceId(), channel->getServiceId()); - g_Font[font_small]->RenderString(xpos, ypos, box_width, "Sid:" , COL_MENUCONTENT_TEXT); - g_Font[font_small]->RenderString(xpos+spaceoffset, ypos, box_width2, buf, COL_MENUCONTENT_TEXT); - - //tsid - ypos+= sheight; - snprintf(buf, sizeof(buf), "0x%04X (%i)", channel->getTransportStreamId(), channel->getTransportStreamId()); - g_Font[font_small]->RenderString(xpos, ypos, box_width, "TSid:" , COL_MENUCONTENT_TEXT); - g_Font[font_small]->RenderString(xpos+spaceoffset, ypos, box_width2, buf, COL_MENUCONTENT_TEXT); - - //pmtpid - ypos+= sheight; - pmt_version = channel->getPmtVersion(); - snprintf(buf, sizeof(buf), "0x%04X (%i) [0x%02X]", channel->getPmtPid(), channel->getPmtPid(), pmt_version); - g_Font[font_small]->RenderString(xpos, ypos, box_width, "PMTpid:", COL_MENUCONTENT_TEXT); - g_Font[font_small]->RenderString(xpos+spaceoffset, ypos, box_width2, buf, COL_MENUCONTENT_TEXT); - - //vpid - ypos+= sheight; - if ( g_RemoteControl->current_PIDs.PIDs.vpid > 0 ){ - snprintf(buf, sizeof(buf), "0x%04X (%i)", g_RemoteControl->current_PIDs.PIDs.vpid, g_RemoteControl->current_PIDs.PIDs.vpid ); } else { - snprintf(buf, sizeof(buf), "%s", g_Locale->getText(LOCALE_STREAMINFO_NOT_AVAILABLE)); - } - g_Font[font_small]->RenderString(xpos, ypos, box_width, "Vpid:" , COL_MENUCONTENT_TEXT); - g_Font[font_small]->RenderString(xpos+spaceoffset, ypos, box_width2, buf, COL_MENUCONTENT_TEXT); - //apid - ypos+= sheight; - g_Font[font_small]->RenderString(xpos, ypos, box_width, "Apid(s):" , COL_MENUCONTENT_TEXT); - if (g_RemoteControl->current_PIDs.APIDs.empty()){ - snprintf(buf, sizeof(buf), "%s", g_Locale->getText(LOCALE_STREAMINFO_NOT_AVAILABLE)); - } else { - unsigned int sw=spaceoffset; - for (unsigned int li= 0; (licurrent_PIDs.APIDs.size()) && (li<16); li++) + // audio pids + if (!g_RemoteControl->current_PIDs.APIDs.empty()){ + for (unsigned int li= 0; li < g_RemoteControl->current_PIDs.APIDs.size(); li++) { - snprintf(buf, sizeof(buf), "0x%04X (%i)", g_RemoteControl->current_PIDs.APIDs[li].pid, g_RemoteControl->current_PIDs.APIDs[li].pid ); - if (li == g_RemoteControl->current_PIDs.PIDs.selected_apid){ - g_Font[font_small]->RenderString(xpos+sw, ypos, box_width2, buf, COL_MENUHEAD_TEXT); - } - else{ - g_Font[font_small]->RenderString(xpos+sw, ypos, box_width2, buf, COL_MENUCONTENT_TEXT); - } - sw = g_Font[font_small]->getRenderWidth(buf)+sw+10; - if (((li+1)%4 == 0) &&(g_RemoteControl->current_PIDs.APIDs.size()-1 > li)){ // if we have lots of apids, put "intermediate" line with pids - ypos+= sheight; - sw=spaceoffset; - } + r.key = li ? "" : "Apid(s): "; + i = g_RemoteControl->current_PIDs.APIDs[li].pid; + std::string strpid = to_string(i); + std::string details(" "); + for (std::vector >::iterator it = streamdata.begin(); it != streamdata.end(); ++it) + if ((*it)["pid"] == strpid) { + details = (*it)["language"]; + if (details != " ") + details += ", "; + details += (*it)["codec"]; + break; + } + if (details == " ") + details.clear(); + snprintf(buf, sizeof(buf), "0x%04X (%i)%s", i, i, details.c_str()); + r.val = buf; + r.col = (li == g_RemoteControl->current_PIDs.PIDs.selected_apid) ? COL_MENUHEAD_TEXT : COL_MENUCONTENT_TEXT; + v.push_back(r); } } + r.key = r.val = ""; + v.push_back(r); + + // picon + r.key = "Picon"; + r.key += ": "; + snprintf(buf, sizeof(buf), "%llx.png", channel->getChannelID() & 0xFFFFFFFFFFFFULL); + r.val = buf; + r.col = COL_MENUCONTENT_TEXT; + r.f = g_Font[font_small]; + v.push_back(r); + // onid + r.key = "ONid: "; + i = channel->getOriginalNetworkId(); + snprintf(buf, sizeof(buf), "0x%04X (%i)", i, i); + r.val = buf; + r.col = COL_MENUCONTENT_TEXT; + r.f = g_Font[font_small]; + v.push_back(r); + + // sid + r.key = "Sid: "; + i = channel->getServiceId(); + snprintf(buf, sizeof(buf), "0x%04X (%i)", i, i); + r.val = buf; + r.col = COL_MENUCONTENT_TEXT; + r.f = g_Font[font_small]; + v.push_back(r); + + // tsid + r.key = "TSid: "; + i = channel->getTransportStreamId(); + snprintf(buf, sizeof(buf), "0x%04X (%i)", i, i); + r.val = buf; + r.col = COL_MENUCONTENT_TEXT; + r.f = g_Font[font_small]; + v.push_back(r); + + // pmtpid + r.key = "PMTpid: "; + i = channel->getPmtPid(); + pmt_version = channel->getPmtVersion(); + snprintf(buf, sizeof(buf), "0x%04X (%i) [0x%02X]", i, i, pmt_version); + r.val = buf; + r.col = COL_MENUCONTENT_TEXT; + r.f = g_Font[font_small]; + v.push_back(r); + //vtxtpid - ypos += sheight; - if ( g_RemoteControl->current_PIDs.PIDs.vtxtpid == 0 ) - snprintf(buf, sizeof(buf), "%s", g_Locale->getText(LOCALE_STREAMINFO_NOT_AVAILABLE)); - else - snprintf(buf, sizeof(buf), "0x%04X (%i)", g_RemoteControl->current_PIDs.PIDs.vtxtpid, g_RemoteControl->current_PIDs.PIDs.vtxtpid ); - g_Font[font_small]->RenderString(xpos, ypos, box_width, "VTXTpid:" , COL_MENUCONTENT_TEXT); - g_Font[font_small]->RenderString(xpos+spaceoffset, ypos, box_width2, buf, COL_MENUCONTENT_TEXT); + if (g_RemoteControl->current_PIDs.PIDs.vtxtpid) { + r.key = "VTXTpid: "; + i = g_RemoteControl->current_PIDs.PIDs.vtxtpid; + snprintf(buf, sizeof(buf), "0x%04X (%i)", i, i); + r.val = buf; + r.col = COL_MENUCONTENT_TEXT; + r.f = g_Font[font_small]; + v.push_back(r); + } + } + spaceoffset = 0; + for (std::vector::iterator it = v.begin(); it != v.end(); ++it) + spaceoffset = std::max(spaceoffset, it->f->getRenderWidth(it->key)); + + spaceoffset = std::max(spaceoffset, g_Font[font_info]->getRenderWidth(std::string(g_Locale->getText(LOCALE_STREAMINFO_BITRATE)) + ": ")); + + for (std::vector::iterator it = v.begin(); it != v.end(); ++it) { + it->f->RenderString (xpos, ypos, spaceoffset, it->key, COL_MENUCONTENT_TEXT); + std::string text = it->val.c_str(); + it->f->RenderString (xpos + spaceoffset, ypos, box_width - spaceoffset, text, it->col); + ypos += it->f->getHeight(); + } + if(box_h == 0) box_h = ypos - ypos1; yypos = ypos; + if (!mp) paintCASystem(xpos,ypos); - } } #define NUM_CAIDS 11 void CStreamInfo2::paintCASystem(int xpos, int ypos) { - unsigned short i; - int box_width = width*2/3-10; - if (box_h2 > ypos+(iheight*2)) - frameBuffer->paintBox(0, ypos+(iheight*2), box_width, box_h2, COL_MENUCONTENT_PLUS_0); + int ypos1 = ypos; + + if(box_h2 > 0) + frameBuffer->paintBoxRel (0, ypos, box_width, box_h2, COL_MENUCONTENT_PLUS_0); std::string casys[NUM_CAIDS]={"Irdeto:","Betacrypt:","Seca:","Viaccess:","Nagra:","Conax: ","Cryptoworks:","Videoguard:","EBU:","XCrypt:","PowerVU:"}; bool caids[NUM_CAIDS]; @@ -878,12 +1105,25 @@ void CStreamInfo2::paintCASystem(int xpos, int ypos) if(!channel) return; - for(i = 0; i < NUM_CAIDS; i++) { - array[i] = g_Font[font_info]->getRenderWidth(casys[i]); + for(int i = 0; i < NUM_CAIDS; i++) { + array[i] = g_Font[font_small]->getRenderWidth(casys[i]); caids[i] = false; } - int spaceoffset = 0; + int acaid = 0; + FILE *f = fopen("/tmp/ecm.info", "rt"); + if (f) { + char buf[80]; + if (fgets(buf, sizeof(buf), f) != NULL) { + int i = 0; + while (buf[i] != '0') + i++; + sscanf(&buf[i], "%X", &acaid); + } + fclose(f); + } + + int off = 0; for(casys_map_iterator_t it = channel->camap.begin(); it != channel->camap.end(); ++it) { int idx = -1; @@ -928,33 +1168,35 @@ void CStreamInfo2::paintCASystem(int xpos, int ypos) snprintf(tmp, sizeof(tmp)," 0x%04X", (*it)); casys[idx] += tmp; caids[idx] = true; - if(spaceoffset < array[idx]) - spaceoffset = array[idx]; + if(off < array[idx]) + off = array[idx]; } } - spaceoffset+=4; + off+=4; bool cryptsysteme = true; for(int ca_id = 0; ca_id < NUM_CAIDS; ca_id++){ if(caids[ca_id] == true){ if(cryptsysteme){ ypos += iheight; - g_Font[font_info]->RenderString(xpos , ypos, box_width, "Conditional access:" , COL_MENUCONTENT_TEXT); + g_Font[font_info]->RenderString(xpos , ypos, box_width, g_Locale->getText(LOCALE_STREAMINFO_CASYSTEMS), COL_MENUCONTENT_TEXT); cryptsysteme = false; } ypos += sheight; - if (ypos > max_height) { - ypos -= sheight; - break; - } int width_txt = 0, index = 0; const char *tok = " "; std::string::size_type last_pos = casys[ca_id].find_first_not_of(tok, 0); std::string::size_type pos = casys[ca_id].find_first_of(tok, last_pos); while (std::string::npos != pos || std::string::npos != last_pos){ - g_Font[font_small]->RenderString(xpos + width_txt, ypos, box_width, casys[ca_id].substr(last_pos, pos - last_pos).c_str() , COL_MENUCONTENT_TEXT); + int col = COL_MENUCONTENT_TEXT; + if (index > 0) { + int id; + if (1 == sscanf(casys[ca_id].substr(last_pos, pos - last_pos).c_str(), "%X", &id) && acaid == id) + col = COL_MENUHEAD_TEXT; + } + g_Font[font_small]->RenderString(xpos + width_txt, ypos, box_width, casys[ca_id].substr(last_pos, pos - last_pos), col); if(index == 0) - width_txt = spaceoffset; + width_txt = off; else width_txt += g_Font[font_small]->getRenderWidth(casys[ca_id].substr(last_pos, pos - last_pos))+10; index++; @@ -965,8 +1207,8 @@ void CStreamInfo2::paintCASystem(int xpos, int ypos) } } } - if (box_h2 < ypos) - box_h2 = ypos; + if(box_h2 == 0) + box_h2 = ypos - ypos1; } /* @@ -983,88 +1225,114 @@ long delta_time_ms (struct timeval *tv, struct timeval *last_tv) return timeval_to_ms (tv) - timeval_to_ms (last_tv); } -static cDemux * dmx = NULL; - -int CStreamInfo2::ts_setup () +bool CStreamInfo2::ts_setup () { -#if 0 - if (g_RemoteControl->current_PIDs.PIDs.vpid == 0) - return -1; -#endif - - short ret = -1; if (mp) { mp->GetReadCount(); + if (pthread_create(&probe_thread, NULL, probeStreams, this)) { + fprintf(stderr, "creating probe_thread failed\n"); + } } else { - - unsigned short vpid, apid = 0; - - vpid = g_RemoteControl->current_PIDs.PIDs.vpid; - if( !g_RemoteControl->current_PIDs.APIDs.empty() ) - apid = g_RemoteControl->current_PIDs.APIDs[g_RemoteControl->current_PIDs.PIDs.selected_apid].pid; - - if(vpid == 0 && apid == 0) - return ret; + probebuf_length = 0; + probebuf_off = 0; + abort_probing = false; + probed = false; dmx = new cDemux(0); if(!dmx) - return ret; -#define TS_LEN 188 -#define TS_BUF_SIZE (TS_LEN * 2048) /* fix dmx buffer size */ + return false; dmxbuf = new unsigned char[TS_BUF_SIZE]; if(!dmxbuf){ delete dmx; dmx = NULL; - return ret; + return false; } - dmx->Open(DMX_TP_CHANNEL, NULL, 3 * 3008 * 62); + dmx->Open(DMX_TP_CHANNEL, NULL, (8 * 1024 * 1024 / TS_LEN) * TS_LEN); - if(vpid > 0) { - dmx->pesFilter(vpid); - if(apid > 0) - dmx->addPid(apid); - } else - dmx->pesFilter(apid); + std::vector pids; + + for (unsigned int i = 0; i < g_RemoteControl->current_PIDs.APIDs.size(); i++) + pids.push_back(g_RemoteControl->current_PIDs.APIDs[i].pid); + probebuf_size = 2 * ((100000 * pids.size()) / TS_LEN) * TS_LEN; + + if (g_RemoteControl->current_PIDs.PIDs.vpid) + pids.push_back(g_RemoteControl->current_PIDs.PIDs.vpid); +#if 0 + if (g_RemoteControl->current_PIDs.PIDs.vtxtpid) + pids.push_back(g_RemoteControl->current_PIDs.PIDs.vtxtpid); + + pids.push_back(0); + pids.push_back(g_RemoteControl->current_PIDs.PIDs.pmtpid); +#else + if (pids.empty()) { + delete dmx; + dmx = NULL; + delete[] dmxbuf; + dmxbuf = NULL; + return false; + } +#endif + std::vector::iterator it = pids.begin(); + dmx->pesFilter(*it); + ++it; + for (; it != pids.end(); ++it) + dmx->addPid(*it); + probebuf = new unsigned char[probebuf_size]; dmx->Start(true); + if (pthread_create(&probe_thread, NULL, probeStreams, this)) { + fprintf(stderr, "creating probe_thread failed\n"); + delete[] probebuf; + probebuf = NULL; + } } gettimeofday (&first_tv, NULL); last_tv.tv_sec = first_tv.tv_sec; last_tv.tv_usec = first_tv.tv_usec; - ret = b_total = 0; - return ret; + b_total = 0; + return true; } -int CStreamInfo2::update_rate () +bool CStreamInfo2::update_rate () { - int ret = 0; - int timeout = 100; - int b_len = 0; - if(!dmx && !mp) + if(!mp && !dmx) return 0; - if (mp) { - usleep(timeout * 1000); - b_len = mp->GetReadCount(); - } else { - int64_t start = time_monotonic_ms(); - /* always sample for ~100ms */ - while (time_monotonic_ms() - start < timeout) - { - ret = dmx->Read(dmxbuf, TS_BUF_SIZE, 10); - if (ret >= 0) - b_len += ret; + int timeout = 100; + + int b_len; + if (mp) { + usleep(timeout * 1000); + b_len = mp->GetReadCount(); + } else { + b_len = dmx->Read(dmxbuf, TS_BUF_SIZE, timeout); + if (probebuf && b_len > TS_LEN - 1 && probebuf_length < probebuf_size) { + OpenThreads::ScopedLock lock(probe_mutex); + if (probebuf) { + int len = (b_len / TS_LEN) * TS_LEN; + uint16_t vpid = g_RemoteControl->current_PIDs.PIDs.vpid; + if (vpid) { + unsigned char *p = dmxbuf, *p_end = dmxbuf + len; + for (; probebuf_size - TS_LEN > probebuf_length && p < p_end; p += TS_LEN) + if (vpid != (0x1fff & (p[1] << 8 | p[2]))) { + memcpy(probebuf + probebuf_length, p, TS_LEN); + probebuf_length += TS_LEN; + } + } else { + int n = std::min(len, (int) probebuf_size - (int) probebuf_length); + memcpy(probebuf + probebuf_length, dmxbuf, n); + probebuf_length += n; + } + } } - //printf("ts: read %d time %" PRId64 "\n", b_len, time_monotonic_ms() - start); } - //printf("ts: read %d\n", b_len); long b = b_len; if (b <= 0) - return 0; + return false; gettimeofday (&tv, NULL); @@ -1088,32 +1356,30 @@ int CStreamInfo2::update_rate () last_tv.tv_sec = tv.tv_sec; last_tv.tv_usec = tv.tv_usec; - - return 1; + return true; } int CStreamInfo2::ts_close () { - if(dmx) + abort_probing = true; + if (probe_thread) + pthread_join(probe_thread, NULL); + + if(dmx) { delete dmx; dmx = NULL; - if(dmxbuf) + } + if(dmxbuf) { delete [] dmxbuf; dmxbuf = NULL; + } return 0; } void CStreamInfo2::showSNR () { - /* sig_text_y + sheight + 4 + 5 is upper limit of ber/snr/sig numbers - * sheight*3 is 3x sig numbers + 1/2 sheight */ - int snr_y = sig_text_y + 4+5 + sheight*9 / 2; - int snr_h = 50; - if (snr_y + snr_h > max_height - 10) - return; - if (signalbox == NULL) - { - signalbox = new CSignalBox(sigBox_x, snr_y, 240, snr_h, frontend); + if (signalbox == NULL){ + signalbox = new CSignalBox(width - width/3 - 10, y + 10 + 2*(height/3 + hheight) + 3*sheight, width/3, 2*iheight, frontend); signalbox->setColorBody(COL_MENUCONTENT_PLUS_0); signalbox->setTextColor(COL_MENUCONTENT_TEXT); signalbox->doPaintBg(true); diff --git a/src/gui/streaminfo2.h b/src/gui/streaminfo2.h index eaf0b9da5..c86c07c6a 100644 --- a/src/gui/streaminfo2.h +++ b/src/gui/streaminfo2.h @@ -28,18 +28,21 @@ #include #include #include +#include +#include +struct AVFormatContext; + class CFrameBuffer; -class COSDFader; class CStreamInfo2 : public CMenuTarget { private: CFrameBuffer *frameBuffer; CFrontend *frontend; - CComponentsPIP * pip; + CComponentsPIP *pip; CMoviePlayerGui *mp; - COSDFader fader; + COSDFader fader; int x; int y; int width; @@ -67,7 +70,11 @@ class CStreamInfo2 : public CMenuTarget int sig_text_snr_x; int sig_text_rate_x; int average_bitrate_pos; - int average_bitrate_offset; + + int techinfo_xpos, techinfo_ypos; + int box_width; + + int spaceoffset; unsigned int scaling; unsigned int pmt_version; int box_h,box_h2; @@ -81,6 +88,8 @@ class CStreamInfo2 : public CMenuTarget unsigned int short_average, max_short_average, min_short_average; } rate; + std::vector > streamdata; + int doSignalStrengthLoop(); struct timeval tv, last_tv, first_tv; @@ -88,9 +97,21 @@ class CStreamInfo2 : public CMenuTarget uint64_t abit_s; uint64_t b_total; unsigned char *dmxbuf; - int update_rate(); - int ts_setup(); + unsigned char *probebuf; + unsigned int probebuf_off; + unsigned int probebuf_size; + unsigned int probebuf_length; + OpenThreads::Mutex probe_mutex; + pthread_t probe_thread; + bool probed; + + bool update_rate(); + bool ts_setup(); int ts_close(); + static void *probeStreams(void *arg); + void probeStreams(); + void analyzeStreams(AVFormatContext *avfc); + void analyzeStream(AVFormatContext *avfc, unsigned int i); void paint(int mode); void paint_techinfo(int x, int y); @@ -103,6 +124,7 @@ class CStreamInfo2 : public CMenuTarget void showSNR (); public: + bool abort_probing; CStreamInfo2(); ~CStreamInfo2(); @@ -110,6 +132,7 @@ class CStreamInfo2 : public CMenuTarget void hide(); int exec(CMenuTarget* parent, const std::string & actionKey); + int readPacket(uint8_t *buf, int buf_size); }; #endif diff --git a/src/system/locals.h b/src/system/locals.h index 03da88351..5b7705c6c 100644 --- a/src/system/locals.h +++ b/src/system/locals.h @@ -2318,6 +2318,7 @@ typedef enum LOCALE_STREAMINFO_AUDIOTYPE_UNKNOWN, LOCALE_STREAMINFO_AVERAGE_BITRATE, LOCALE_STREAMINFO_BITRATE, + LOCALE_STREAMINFO_CASYSTEMS, LOCALE_STREAMINFO_FRAMERATE, LOCALE_STREAMINFO_FRAMERATE_UNKNOWN, LOCALE_STREAMINFO_HEAD, diff --git a/src/system/locals_intern.h b/src/system/locals_intern.h index b6cfdcedf..eb745dace 100644 --- a/src/system/locals_intern.h +++ b/src/system/locals_intern.h @@ -2318,6 +2318,7 @@ const char * locale_real_names[] = "streaminfo.audiotype_unknown", "streaminfo.average_bitrate", "streaminfo.bitrate", + "streaminfo.casystems", "streaminfo.framerate", "streaminfo.framerate_unknown", "streaminfo.head",