vdr-plugin-softhddevice-drm-gles 1.6.4-d0291bb
mediaplayer.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: AGPL-3.0-or-later
2
17#include <cstdlib>
18#include <fstream>
19#include <string>
20
21extern "C" {
22#include <libavcodec/avcodec.h>
23#include <libavformat/avformat.h>
24}
25
26#include <vdr/player.h>
27
28#include "audio.h"
29#include "logger.h"
30#include "misc.h"
31#include "mediaplayer.h"
32#include "softhddevice.h"
33#include "softhdmenu.h"
34
40cSoftHdPlayer *cSoftHdControl::m_pPlayer = NULL; //< Player instance
43/*****************************************************************************
44 * cPlaylistEntry
45 ****************************************************************************/
46
53 : m_path(path)
54{
55 m_file = m_path.substr(m_path.find_last_of("/") +1, std::string::npos);
56
57 std::string subString = m_path.substr(0, m_path.find_last_of("/"));
58 m_subFolder = subString.substr(subString.find_last_of("/") +1, std::string::npos);
59
60 std::string folderString = m_path.substr(0, subString.find_last_of("/"));
61 m_folder = folderString.substr(folderString.find_last_of("/") +1, std::string::npos);
62}
63
68{
69 return (m_folder + " - " + m_subFolder + " - " + m_file);
70}
71
72/*****************************************************************************
73 * cSoftHdPlayer (cPlayer mediaplayer)
74 ****************************************************************************/
75
83static bool IsM3UPlaylist(char *source)
84{
85 return (strcasestr(source, ".M3U") && !strcasestr(source, ".M3U8"));
86}
87
95 : cPlayer(pmAudioVideo),
96 m_pDevice(device),
97 m_pAudio(m_pDevice->Audio())
98{
99 m_pSource = (char *) malloc(1 + strlen(url));
101
105 } else
106 m_pFirstEntry = m_pCurrentEntry = nullptr;
107
108 LOGDEBUG2(L_MEDIA, "mediaplayer: %s: player started", __FUNCTION__);
109}
110
112{
113 m_stopped = true;
115
116 while (m_pFirstEntry) {
118 m_pFirstEntry = entry->GetNextEntry();
119 delete entry;
120 m_entries--;
121 }
122
123 LOGDEBUG2(L_MEDIA, "mediaplayer: %s: player stopped", __FUNCTION__);
124}
125
134{
135 LOGDEBUG2(L_MEDIA, "mediaplayer: %s: %s", __FUNCTION__, on ? "On" : "Off");
136 if (on)
137 Start();
138}
139
145{
146 LOGDEBUG2(L_MEDIA, "mediaplayer: %s:", __FUNCTION__);
147 m_noModify = false;
148
150 while(m_pCurrentEntry) {
151 m_jumpSec = 0;
152 Play(m_pCurrentEntry->GetPath().c_str());
153
154 if (!m_noModify) {
156
157 if (m_random) {
158 srand (time (NULL));
159 SetEntry(std::rand() % (m_entries));
160 }
161 }
162 m_noModify = 0;
163
164 if (cSoftHdMenu::Menu())
165 cSoftHdMenu::Menu()->PlayListMenu();
166 }
167 } else
169
171 usleep(5000);
172
173 cSoftHdControl::Control()->Close();
174}
175
182{
183 std::ifstream inputFile;
184 cPlaylistEntry *lastEntry = nullptr;
185 m_entries = 0;
186
187 inputFile.open(playlist);
188 if (!inputFile.good()) {
189 LOGERROR("mediaplayer: %s: open PL %s failed", __FUNCTION__, playlist);
190 return;
191 }
192
193 while (!inputFile.eof()) {
194 std::string s;
196 if (s.size() && s.compare(0, 1, "#")) {
198
199 if (!lastEntry)
201 else
202 lastEntry->SetNextEntry(entry);
203
205 m_entries++;
206 }
207 }
208
209 inputFile.close();
210}
211
218{
221
222 for (int i = 0; i < index ; i++) {
223 entry = entry->GetNextEntry();
224 }
225
227 m_noModify = true;
228 m_stopped = true;
229}
230
236void cSoftHdPlayer::Play(const char *url)
237{
238#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(59,0,100)
240#else
241 const AVCodec *videoCodec;
242#endif
243 int err = 0;
244 int audioStreamIdx = 0;
245 int videoStreamIdx;
246 int jumpStreamIdx = 0;
247 int startTime;
248
249 m_stopped = false;
250 m_jumpSec = 0;
251
253 if (avformat_open_input(&format, url, NULL, NULL) != 0) {
254 LOGERROR("mediaplayer: %s: Could not open file '%s'", __FUNCTION__, url);
255 return;
256 }
257#ifdef MEDIA_DEBUG
258 av_dump_format(format, -1, url, 0);
259#endif
260 if (avformat_find_stream_info(format, NULL) < 0) {
261 LOGERROR("mediaplayer: %s: Could not retrieve stream info from file '%s'", __FUNCTION__, url);
262 return;
263 }
264
265 for (unsigned int i = 0; i < format->nb_streams; i++) {
266 if (format->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
267 m_pDevice->SetAudioCodec(format->streams[i]->codecpar->codec_id,
268 format->streams[i]->codecpar, format->streams[i]->time_base);
270 break;
271 }
272 }
273
275
276 if (videoStreamIdx < 0) {
277 LOGDEBUG2(L_MEDIA, "mediaplayer: %s: stream does not seem to contain video", __FUNCTION__);
278 } else {
280 format->streams[videoStreamIdx]->codecpar,
281 format->streams[videoStreamIdx]->time_base);
283 }
284
285 m_duration = format->duration / AV_TIME_BASE;
286 startTime = format->start_time / AV_TIME_BASE;
287
288 AVPacket *packet = nullptr;
289 while (!m_stopped) {
290 if (!packet) {
292 if (!packet) {
293 LOGFATAL("mediaplayer: %s: out of memory", __FUNCTION__);
294 return;
295 }
296
297 err = av_read_frame(format, packet);
298 if (err < 0) {
299 LOGDEBUG2(L_MEDIA, "mediaplayer: %s: av_read_frame error: %s", __FUNCTION__,
300 av_err2str(err));
301 m_stopped = true;
303 break;
304 }
305 }
306
307 if (audioStreamIdx == packet->stream_index) {
309 usleep(packet->duration * AV_TIME_BASE *
310 av_q2d(format->streams[audioStreamIdx]->time_base));
311 } else {
314 packet = nullptr;
315 }
316 } else if (videoStreamIdx == packet->stream_index) {
318 usleep(packet->duration * AV_TIME_BASE *
319 av_q2d(format->streams[videoStreamIdx]->time_base));
320 } else {
321 packet = nullptr;
322 }
323 } else {
325 packet = nullptr;
326 }
327
328 while (m_paused && !m_stopped)
329 sleep(1);
330
331 if (m_jumpSec && format->pb->seekable) {
332 av_seek_frame(format, format->streams[jumpStreamIdx]->index,
333 packet->pts + (int64_t)(m_jumpSec / // - BufferOffset
334 av_q2d(format->streams[jumpStreamIdx]->time_base)), 0);
335 m_pDevice->Clear();
336 m_jumpSec = 0;
337
338 if (packet) {
340 packet = nullptr;
341 }
342 }
343
344 if (m_stopped) {
345 m_pDevice->Clear();
346 break;
347 }
348 }
349
350 if (packet)
352
353 m_duration = 0;
354 m_currentTime = 0;
355
356 avformat_close_input(&format);
357 avformat_free_context(format);
358}
359
360/*****************************************************************************
361 * cSoftHdControl (cControl mediaplayer)
362 ****************************************************************************/
363
371 : cControl(m_pPlayer = new cSoftHdPlayer(url, device)),
372 m_pDevice(device)
373{
374 m_pControl = this;
375}
376
383
388{
389 LOGDEBUG2(L_MEDIA, "mediaplayer: %s:", __FUNCTION__);
390 if (m_pOsd)
391 delete m_pOsd;
392
393 m_pOsd = NULL;
394}
395
400{
401 if (!m_pOsd) {
402 LOGDEBUG2(L_MEDIA, "mediaplayer: %s: get OSD", __FUNCTION__);
403 m_pOsd = Skins.Current()->DisplayReplay(false);
404 }
405
406 m_pOsd->SetTitle(m_pPlayer->GetCurrentPlaylistEntry() ? m_pPlayer->GetCurrentPlaylistEntry()->GetPath().c_str() : m_pPlayer->GetSource());
407 m_pOsd->SetProgress(m_pPlayer->GetCurrentTime(), m_pPlayer->GetDuration());
408 m_pOsd->SetCurrent(IndexToHMSF(m_pPlayer->GetCurrentTime(), false, 1));
409 m_pOsd->SetTotal(IndexToHMSF(m_pPlayer->GetDuration(), false, 1));
410
411 Skins.Flush();
412}
413
420{
421 switch (key) {
422 case kNone:
423 if (m_pOsd)
424 ShowProgress();
425 if (m_closing) {
426 Hide();
427 return osStopReplay;
428 }
429 break;
430 case kOk:
431 if (m_pOsd)
432 Hide();
433 else
434 ShowProgress();
435 break;
436 case kPlay:
437 case kUp:
438 if (m_pPlayer->IsPaused()) {
439 m_pPlayer->Pause(false);
440 m_pDevice->Play();
441 }
442 break;
443 case kGreen:
444 m_pPlayer->JumpSec(-60);
445 break;
446 case kYellow:
447 m_pPlayer->JumpSec(60);
448 break;
449 case kLeft:
450 m_pPlayer->JumpSec(-5);
451 break;
452 case kRight:
453 m_pPlayer->JumpSec(5);
454 break;
455 case kBlue:
456 case kBack:
457 Hide();
458 m_pPlayer->Stop();
459 return osStopReplay;
460 case kPause:
461 case kDown:
462 if (m_pPlayer->IsPaused()) {
463 m_pPlayer->Pause(false);
464 m_pDevice->Play();
465 } else {
466 m_pPlayer->Pause(true);
467 m_pDevice->Freeze();
468 }
469 break;
470 case kNext:
471 m_pPlayer->Stop();
472 break;
473 default:
474 break;
475 }
476
477 return osContinue;
478}
Audio and Alsa Interface Header File.
Playlist Entry.
Definition mediaplayer.h:34
std::string m_path
Definition mediaplayer.h:43
std::string m_file
Definition mediaplayer.h:44
std::string m_folder
Definition mediaplayer.h:46
std::string m_subFolder
Definition mediaplayer.h:45
std::string OsdItemString(void)
Compose a full-path-string for the OSD entry.
std::string GetPath(void)
Definition mediaplayer.h:41
cPlaylistEntry * GetNextEntry(void)
Definition mediaplayer.h:39
cPlaylistEntry(std::string)
Builds the playlist entry from a file name.
int64_t GetHardwareOutputPtsMs(void)
Get the hardware output PTS in milliseconds.
Definition audio.cpp:1043
Media Player Control.
virtual eOSState ProcessKey(eKeys)
Handle a key event.
cSoftHdControl(const char *, cSoftHdDevice *)
Create a new control interface and corresponding player.
static cSoftHdControl * Control()
cSoftHdDevice * m_pDevice
cSkinDisplayReplay * m_pOsd
void ShowProgress()
Open the replay OSD.
virtual void Hide(void)
Close the replay OSD.
virtual ~cSoftHdControl()
Output Device Implementation.
int PlayAudioPkts(AVPacket *)
Play an audio packet.
virtual void Clear(void)
Clears all video and audio data from the device.
void SetAudioCodec(enum AVCodecID, AVCodecParameters *, AVRational)
Open an audio codec.
virtual void Play(void)
Sets the device into play mode (after a previous trick mode, or pause)
int PlayVideoPkts(AVPacket *)
Play a video packet.
virtual void Freeze(void)
Puts the device into "freeze frame" mode.
void SetVideoCodec(enum AVCodecID, AVCodecParameters *, AVRational)
Open a video codec.
static cSoftHdMenu * Menu()
Definition softhdmenu.h:48
Media Player.
Definition mediaplayer.h:57
std::atomic< bool > m_stopped
Definition mediaplayer.h:93
char * m_pSource
Definition mediaplayer.h:87
virtual void Action(void)
Main thread action which invokes replay start.
virtual ~cSoftHdPlayer()
std::atomic< int > m_jumpSec
Definition mediaplayer.h:91
cPlaylistEntry * m_pFirstEntry
Definition mediaplayer.h:84
std::atomic< bool > m_random
Definition mediaplayer.h:94
void ReadPlaylist(const char *)
Read the playlist file.
cPlaylistEntry * m_pCurrentEntry
Definition mediaplayer.h:85
virtual void Activate(bool On)
Start player thread.
cSoftHdAudio * m_pAudio
Definition mediaplayer.h:90
std::atomic< bool > m_paused
Definition mediaplayer.h:92
cSoftHdDevice * m_pDevice
Definition mediaplayer.h:89
cSoftHdPlayer(const char *, cSoftHdDevice *)
Create a new player for a file or playlist.
void SetEntry(int)
Set the current entry to play.
void Play(const char *)
Play a file.
static bool IsM3UPlaylist(char *source)
Returns true, if the playlist is a m3u playlist.
static cSoftHdPlayer * m_pPlayer
static cSoftHdControl * m_pControl
Control instance.
#define LOGDEBUG2
log to LOG_DEBUG and add a prefix
Definition logger.h:47
#define LOGERROR
log to LOG_ERR
Definition logger.h:39
#define AV_NOPTS_VALUE
Definition misc.h:74
#define LOGFATAL
log to LOG_ERR and abort
Definition logger.h:37
#define av_err2str(err)
Definition misc.h:112
@ L_MEDIA
mediaplayer logs
Definition logger.h:64
Logger Header File.
Mediaplayer Header File.
Misc Functions.
Output Device Header File.
Plugin Main Menu Header File.