From 7a0c1e96746586271ceb336a977a645f239631d4 Mon Sep 17 00:00:00 2001 From: "[CST] Focus" Date: Tue, 30 Apr 2013 12:28:15 +0400 Subject: [PATCH] gui/movieplayer.cpp: add subtitle display support for file playback --- src/gui/movieplayer.cpp | 241 +++++++++++++++++++++++++++++++++++++++- src/gui/movieplayer.h | 13 +++ 2 files changed, 248 insertions(+), 6 deletions(-) diff --git a/src/gui/movieplayer.cpp b/src/gui/movieplayer.cpp index 1250969a8..26aa9d97b 100644 --- a/src/gui/movieplayer.cpp +++ b/src/gui/movieplayer.cpp @@ -27,6 +27,7 @@ #include #endif +#define __STDC_CONSTANT_MACROS #include #include @@ -38,6 +39,7 @@ #include #include #include +#include #include #include @@ -304,6 +306,8 @@ bool CMoviePlayerGui::SelectFile() language[i].clear(); } numpida = 0; currentapid = 0; + currentspid = -1; + numsubs = 0; is_file_player = false; p_movie_info = NULL; @@ -356,7 +360,7 @@ bool CMoviePlayerGui::SelectFile() } } else menu_ret = moviebrowser->getMenuRet(); - } + } else { // filebrowser if (filebrowser->exec(Path_local.c_str()) == true) { Path_local = filebrowser->getCurrentDir(); @@ -430,6 +434,8 @@ void CMoviePlayerGui::PlayFile(void) handleMovieBrowser(CRCInput::RC_nokey, position); cutNeutrino(); + clearSubtitle(); + playback->Open(is_file_player ? PLAYMODE_FILE : PLAYMODE_TS); printf("IS FILE PLAYER: %s\n", is_file_player ? "true": "false" ); @@ -528,6 +534,7 @@ void CMoviePlayerGui::PlayFile(void) handleMovieBrowser(0, position); FileTime.update(position, duration); } + showSubtitle(0); if (msg == (neutrino_msg_t) g_settings.mpkey_plugin) { //g_PluginList->start_plugin_by_name (g_settings.movieplayer_plugin.c_str (), pidt); @@ -569,10 +576,15 @@ void CMoviePlayerGui::PlayFile(void) } else if (msg == (neutrino_msg_t) g_settings.mpkey_audio) { selectAudioPid(is_file_player); update_lcd = true; + clearSubtitle(); + } else if ( msg == (neutrino_msg_t) g_settings.mpkey_subtitle) { + selectSubtitle(is_file_player); + clearSubtitle(); + update_lcd = true; } else if (msg == (neutrino_msg_t) g_settings.mpkey_time) { FileTime.switchMode(position, duration); - } else if ((msg == (neutrino_msg_t) g_settings.mpkey_rewind) || - (msg == (neutrino_msg_t) g_settings.mpkey_forward)) { + } else if (!is_file_player && ((msg == (neutrino_msg_t) g_settings.mpkey_rewind) || + (msg == (neutrino_msg_t) g_settings.mpkey_forward))) { int newspeed; if (msg == (neutrino_msg_t) g_settings.mpkey_rewind) { @@ -600,32 +612,44 @@ void CMoviePlayerGui::PlayFile(void) time_forced = true; } } else if (msg == CRCInput::RC_1) { // Jump Backwards 1 minute + clearSubtitle(); playback->SetPosition(-60 * 1000); } else if (msg == CRCInput::RC_3) { // Jump Forward 1 minute + clearSubtitle(); playback->SetPosition(60 * 1000); } else if (msg == CRCInput::RC_4) { // Jump Backwards 5 minutes + clearSubtitle(); playback->SetPosition(-5 * 60 * 1000); } else if (msg == CRCInput::RC_6) { // Jump Forward 5 minutes + clearSubtitle(); playback->SetPosition(5 * 60 * 1000); } else if (msg == CRCInput::RC_7) { // Jump Backwards 10 minutes + clearSubtitle(); playback->SetPosition(-10 * 60 * 1000); } else if (msg == CRCInput::RC_9) { // Jump Forward 10 minutes + clearSubtitle(); playback->SetPosition(10 * 60 * 1000); } else if (msg == CRCInput::RC_2) { // goto start + clearSubtitle(); playback->SetPosition(0, true); } else if (msg == CRCInput::RC_5) { // goto middle + clearSubtitle(); playback->SetPosition(duration/2, true); } else if (msg == CRCInput::RC_8) { // goto end + clearSubtitle(); playback->SetPosition(duration - 60 * 1000, true); } else if (msg == CRCInput::RC_page_up) { + clearSubtitle(); playback->SetPosition(10 * 1000); } else if (msg == CRCInput::RC_page_down) { + clearSubtitle(); playback->SetPosition(-10 * 1000); } else if (msg == CRCInput::RC_0) { // cancel bookmark jump handleMovieBrowser(CRCInput::RC_0, position); } else if (msg == CRCInput::RC_help || msg == CRCInput::RC_info) { callInfoViewer(/*duration, position*/); update_lcd = true; + clearSubtitle(); //showHelpTS(); } else if(timeshift && (msg == CRCInput::RC_text || msg == CRCInput::RC_epg || msg == NeutrinoMessages::SHOW_EPG)) { bool restore = FileTime.IsVisible(); @@ -672,6 +696,8 @@ void CMoviePlayerGui::PlayFile(void) sc->EnableVideo(true); sc->Start(); + } else if ( msg == NeutrinoMessages::EVT_SUBT_MESSAGE) { + showSubtitle(data); } else if ( msg == NeutrinoMessages::ANNOUNCE_RECORD || msg == NeutrinoMessages::RECORD_START) { CNeutrinoApp::getInstance()->handleMsg(msg, data); @@ -697,6 +723,7 @@ void CMoviePlayerGui::PlayFile(void) } else if ( msg <= CRCInput::RC_MaxRC ) { update_lcd = true; + clearSubtitle(); } } @@ -708,6 +735,7 @@ void CMoviePlayerGui::PlayFile(void) } FileTime.hide(); + clearSubtitle(); playback->SetSpeed(1); playback->Close(); @@ -802,7 +830,6 @@ void CMoviePlayerGui::getCurrentAudioName( bool file_player, std::string &audion } bool dumm = true; for (unsigned int count = 0; count < numpida; count++) { - if(currentapid == apids[count]){ if(!file_player){ getAudioName(apids[count], audioname); @@ -1052,7 +1079,7 @@ void CMoviePlayerGui::handleMovieBrowser(neutrino_msg_t msg, int /*position*/) jump_not_until = (position / 1000) + 10; // avoid bookmark jumping for the next 10 seconds, , TODO: might be moved to another key } return; - } + } else if (msg == (neutrino_msg_t) g_settings.mpkey_bookmark) { if (newComHintBox.isPainted() == true) { // yes, let's get the end pos of the jump forward @@ -1112,7 +1139,7 @@ void CMoviePlayerGui::handleMovieBrowser(neutrino_msg_t msg, int /*position*/) DisplayErrorMessage(g_Locale->getText(LOCALE_MOVIEPLAYER_TOOMANYBOOKMARKS)); // UTF-8 } cSelectedMenuBookStart[0].selected = false; // clear for next bookmark menu - } else + } else #endif if (cSelectedMenuBookStart[1].selected == true) { /* Moviebrowser plain bookmark */ @@ -1181,3 +1208,205 @@ void CMoviePlayerGui::showHelpTS() helpbox.addLine(g_Locale->getText(LOCALE_MOVIEPLAYER_TSHELP12)); helpbox.show(LOCALE_MESSAGEBOX_INFO); } + +void CMoviePlayerGui::selectSubtitle(bool file_player) +{ + if (!file_player) + return; + + CMenuWidget APIDSelector(LOCALE_SUBTITLES_HEAD, NEUTRINO_ICON_AUDIO); + APIDSelector.addIntroItems(); + + int select = -1; + CMenuSelectorTarget * selector = new CMenuSelectorTarget(&select); + if(!numsubs) { + playback->FindAllSubs(spids, sub_supported, &numsubs, slanguage); + } + char cnt[5]; + unsigned int count; + for (count = 0; count < numsubs; count++) { + bool enabled = sub_supported[count]; + bool defpid = currentspid >= 0 ? (currentspid == spids[count]) : (count == 0); + std::string title = slanguage[count]; + if (title.empty()) { + char pidnumber[20]; + sprintf(pidnumber, "Stream %d %X", count + 1, spids[count]); + title = pidnumber; + } + sprintf(cnt, "%d", count); + CMenuForwarderNonLocalized * item = new CMenuForwarderNonLocalized(title.c_str(), enabled, NULL, selector, cnt, CRCInput::convertDigitToKey(count + 1)); + APIDSelector.addItem(item, defpid); + } + sprintf(cnt, "%d", count); + APIDSelector.addItem(new CMenuForwarder(LOCALE_SUBTITLES_STOP, true, NULL, selector, cnt, CRCInput::RC_stop), currentspid < 0); + + APIDSelector.exec(NULL, ""); + delete selector; + printf("CMoviePlayerGui::selectSubtitle: selected %d (%x) current %x\n", select, (select >= 0) ? spids[select] : -1, currentspid); + if((select >= 0) && (select < numsubs) && (currentspid != spids[select])) { + currentspid = spids[select]; + playback->SelectSubtitles(currentspid); + printf("[movieplayer] spid changed to %d\n", currentspid); + } else if ( select > 0) { + currentspid = -1; + playback->SelectSubtitles(currentspid); + printf("[movieplayer] spid changed to %d\n", currentspid); + } +} + +extern "C" { +#include +#include +} + +void CMoviePlayerGui::clearSubtitle() +{ + if ((max_x-min_x > 0) && (max_y-min_y > 0)) + frameBuffer->paintBackgroundBoxRel(min_x, min_y, max_x-min_x, max_y-min_y); + + min_x = CFrameBuffer::getInstance()->getScreenWidth(); + min_y = CFrameBuffer::getInstance()->getScreenHeight(); + max_x = CFrameBuffer::getInstance()->getScreenX(); + max_y = CFrameBuffer::getInstance()->getScreenY(); + end_time = 0; +} + +fb_pixel_t * simple_resize32(uint8_t * orgin, uint32_t * colors, int nb_colors, int ox, int oy, int dx, int dy); + +void CMoviePlayerGui::showSubtitle(neutrino_msg_data_t data) +{ + if (!data) { + if (end_time && time_monotonic_ms() > end_time) { + printf("************************* hide subs *************************\n"); + clearSubtitle(); + } + return; + } + AVSubtitle * sub = (AVSubtitle *) data; + + printf("************************* EVT_SUBT_MESSAGE: num_rects %d fmt %d *************************\n", sub->num_rects, sub->format); + if (!sub->num_rects) + return; + + if (sub->format == 0) { + int xres = 0, yres = 0, framerate; + videoDecoder->getPictureInfo(xres, yres, framerate); + + double xc = (double) CFrameBuffer::getInstance()->getScreenWidth(/*true*/)/(double) xres; + double yc = (double) CFrameBuffer::getInstance()->getScreenHeight(/*true*/)/(double) yres; + + clearSubtitle(); + + for (unsigned i = 0; i < sub->num_rects; i++) { + uint32_t * colors = (uint32_t *) sub->rects[i]->pict.data[1]; + + int nw = (double) sub->rects[i]->w * xc; + int nh = (double) sub->rects[i]->h * yc; + int xoff = (double) sub->rects[i]->x * xc; + int yoff = (double) sub->rects[i]->y * yc; + + printf("Draw: #%d at %d,%d size %dx%d colors %d (x=%d y=%d w=%d h=%d) \n", i+1, + sub->rects[i]->x, sub->rects[i]->y, sub->rects[i]->w, sub->rects[i]->h, + sub->rects[i]->nb_colors, xoff, yoff, nw, nh); + + fb_pixel_t * newdata = simple_resize32 (sub->rects[i]->pict.data[0], colors, + sub->rects[i]->nb_colors, sub->rects[i]->w, sub->rects[i]->h, nw, nh); + frameBuffer->blit2FB(newdata, nw, nh, xoff, yoff); + free(newdata); + + min_x = std::min(min_x, xoff); + max_x = std::max(max_x, xoff + nw); + min_y = std::min(min_y, yoff); + max_y = std::max(max_y, yoff + nh); + } + end_time = sub->end_display_time + time_monotonic_ms(); + avsubtitle_free(sub); + delete sub; + return; + } + std::vector subtext; + for (unsigned i = 0; i < sub->num_rects; i++) { + char * txt = NULL; + if (sub->rects[i]->type == SUBTITLE_TEXT) + txt = sub->rects[i]->text; + else if (sub->rects[i]->type == SUBTITLE_ASS) + txt = sub->rects[i]->ass; + printf("subt[%d] type %d [%s]\n", i, sub->rects[i]->type, txt ? txt : ""); + if (txt) { + int len = strlen(txt); + if (len > 10 && memcmp(txt, "Dialogue: ", 10) == 0) { + char* p = txt; + int skip_commas = 4; + /* skip ass times */ + for (int j = 0; j < skip_commas && *p != '\0'; p++) + if (*p == ',') + j++; + /* skip ass tags */ + if (*p == '{') { + char * d = strchr(p, '}'); + if (d) + p += d - p + 1; + } + char * d = strchr(p, '{'); + if (d && strchr(d, '}')) + *d = 0; + + len = strlen(p); + /* remove newline */ + for (int j = len-1; j > 0; j--) { + if (p[j] == '\n' || p[j] == '\r') + p[j] = 0; + else + break; + } + if (*p == '\0') + continue; + txt = p; + } + //printf("title: [%s]\n", txt); + std::string str(txt); + int start = 0, end = 0; + /* split string with \N as newline */ + std::string delim("\\N"); + while ((end = str.find(delim, start)) != string::npos) { + subtext.push_back(str.substr(start, end - start)); + start = end + 2; + } + subtext.push_back(str.substr(start)); + + } + } + for (unsigned i = 0; i < subtext.size(); i++) + printf("subtext %d: [%s]\n", i, subtext[i].c_str()); + printf("********************************************************************\n"); + + if (!subtext.empty()) { + int sh = frameBuffer->getScreenHeight(); + int sw = frameBuffer->getScreenWidth(); + int h = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getHeight(); + int height = h*subtext.size(); + + clearSubtitle(); + + int x[subtext.size()]; + int y[subtext.size()]; + for (unsigned i = 0; i < subtext.size(); i++) { + int w = g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->getRenderWidth (subtext[i].c_str(), true); + x[i] = (sw - w) / 2; + y[i] = sh - height + h*(i + 1); + min_x = std::min(min_x, x[i]); + max_x = std::max(max_x, x[i]+w); + min_y = std::min(min_y, y[i]-h); + max_y = std::max(max_y, y[i]); + } + + frameBuffer->paintBoxRel(min_x, min_y, max_x - min_x, max_y-min_y, COL_MENUCONTENT_PLUS_0); + + for (unsigned i = 0; i < subtext.size(); i++) + g_Font[SNeutrinoSettings::FONT_TYPE_MENU]->RenderString(x[i], y[i], sw, subtext[i].c_str(), COL_MENUCONTENT, 0, true); + + end_time = sub->end_display_time + time_monotonic_ms(); + } + avsubtitle_free(sub); + delete sub; +} diff --git a/src/gui/movieplayer.h b/src/gui/movieplayer.h index df8434f67..febe09fec 100644 --- a/src/gui/movieplayer.h +++ b/src/gui/movieplayer.h @@ -87,6 +87,15 @@ class CMoviePlayerGui : public CMenuTarget unsigned short ac3flags[REC_MAX_APIDS]; unsigned short currentapid, currentac3; + /* subtitles vars */ + unsigned short numsubs; + std::string slanguage[REC_MAX_APIDS]; + unsigned short spids[REC_MAX_APIDS]; + unsigned short sub_supported[REC_MAX_APIDS]; + int currentspid; + int min_x, min_y, max_x, max_y; + time_t end_time; + /* playback from MB */ bool isMovieBrowser; CMovieBrowser* moviebrowser; @@ -124,6 +133,10 @@ class CMoviePlayerGui : public CMenuTarget bool SelectFile(); void updateLcd(); + void selectSubtitle(bool file_player); + void showSubtitle(neutrino_msg_data_t data); + void clearSubtitle(); + CMoviePlayerGui(const CMoviePlayerGui&) {}; CMoviePlayerGui();