vdr-plugin-softhddevice-drm-gles 1.6.2
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
42/*****************************************************************************
43 * cPlaylistEntry
44 ****************************************************************************/
45
52 : m_path(path)
53{
54 m_file = m_path.substr(m_path.find_last_of("/") +1, std::string::npos);
55
56 std::string subString = m_path.substr(0, m_path.find_last_of("/"));
57 m_subFolder = subString.substr(subString.find_last_of("/") +1, std::string::npos);
58
59 std::string folderString = m_path.substr(0, subString.find_last_of("/"));
60 m_folder = folderString.substr(folderString.find_last_of("/") +1, std::string::npos);
61}
62
67{
68 return (m_folder + " - " + m_subFolder + " - " + m_file);
69}
70
71/*****************************************************************************
72 * cSoftHdPlayer (cPlayer mediaplayer)
73 ****************************************************************************/
74
80static bool IsM3UPlaylist(char *source)
81{
82 return (strcasestr(source, ".M3U") && !strcasestr(source, ".M3U8"));
83}
84
92 : cPlayer(pmAudioVideo),
93 m_pDevice(device),
94 m_pAudio(m_pDevice->Audio())
95{
96 m_pSource = (char *) malloc(1 + strlen(url));
98
102 } else
103 m_pFirstEntry = m_pCurrentEntry = nullptr;
104
105 LOGDEBUG2(L_MEDIA, "mediaplayer: %s: player started", __FUNCTION__);
106}
107
109{
110 m_stopped = true;
112
113 while (m_pFirstEntry) {
115 m_pFirstEntry = entry->GetNextEntry();
116 delete entry;
117 m_entries--;
118 }
119
120 LOGDEBUG2(L_MEDIA, "mediaplayer: %s: player stopped", __FUNCTION__);
121}
122
131{
132 LOGDEBUG2(L_MEDIA, "mediaplayer: %s: %s", __FUNCTION__, on ? "On" : "Off");
133 if (on)
134 Start();
135}
136
142{
143 LOGDEBUG2(L_MEDIA, "mediaplayer: %s:", __FUNCTION__);
144 m_noModify = false;
145
147 while(m_pCurrentEntry) {
148 m_jumpSec = 0;
149 Play(m_pCurrentEntry->GetPath().c_str());
150
151 if (!m_noModify) {
153
154 if (m_random) {
155 srand (time (NULL));
156 SetEntry(std::rand() % (m_entries));
157 }
158 }
159 m_noModify = 0;
160
161 if (cSoftHdMenu::Menu())
162 cSoftHdMenu::Menu()->PlayListMenu();
163 }
164 } else
166
168 usleep(5000);
169
170 cSoftHdControl::Control()->Close();
171}
172
179{
180 std::ifstream inputFile;
181 cPlaylistEntry *lastEntry = nullptr;
182 m_entries = 0;
183
184 inputFile.open(playlist);
185 if (!inputFile.good()) {
186 LOGERROR("mediaplayer: %s: open PL %s failed", __FUNCTION__, playlist);
187 return;
188 }
189
190 while (!inputFile.eof()) {
191 std::string s;
193 if (s.size() && s.compare(0, 1, "#")) {
195
196 if (!lastEntry)
198 else
199 lastEntry->SetNextEntry(entry);
200
202 m_entries++;
203 }
204 }
205
206 inputFile.close();
207}
208
215{
218
219 for (int i = 0; i < index ; i++) {
220 entry = entry->GetNextEntry();
221 }
222
224 m_noModify = true;
225 m_stopped = true;
226}
227
233void cSoftHdPlayer::Play(const char *url)
234{
235#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(59,0,100)
237#else
238 const AVCodec *videoCodec;
239#endif
240 int err = 0;
241 int audioStreamIdx = 0;
242 int videoStreamIdx;
243 int jumpStreamIdx = 0;
244 int startTime;
245
246 m_stopped = false;
247 m_jumpSec = 0;
248
250 if (avformat_open_input(&format, url, NULL, NULL) != 0) {
251 LOGERROR("mediaplayer: %s: Could not open file '%s'", __FUNCTION__, url);
252 return;
253 }
254#ifdef MEDIA_DEBUG
255 av_dump_format(format, -1, url, 0);
256#endif
257 if (avformat_find_stream_info(format, NULL) < 0) {
258 LOGERROR("mediaplayer: %s: Could not retrieve stream info from file '%s'", __FUNCTION__, url);
259 return;
260 }
261
262 for (unsigned int i = 0; i < format->nb_streams; i++) {
263 if (format->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
264 m_pDevice->SetAudioCodec(format->streams[i]->codecpar->codec_id,
265 format->streams[i]->codecpar, format->streams[i]->time_base);
267 break;
268 }
269 }
270
272
273 if (videoStreamIdx < 0) {
274 LOGDEBUG2(L_MEDIA, "mediaplayer: %s: stream does not seem to contain video", __FUNCTION__);
275 } else {
277 format->streams[videoStreamIdx]->codecpar,
278 format->streams[videoStreamIdx]->time_base);
280 }
281
282 m_duration = format->duration / AV_TIME_BASE;
283 startTime = format->start_time / AV_TIME_BASE;
284
285 AVPacket *packet = nullptr;
286 while (!m_stopped) {
287 if (!packet) {
289 if (!packet) {
290 LOGFATAL("mediaplayer: %s: out of memory", __FUNCTION__);
291 return;
292 }
293
294 err = av_read_frame(format, packet);
295 if (err < 0) {
296 LOGDEBUG2(L_MEDIA, "mediaplayer: %s: av_read_frame error: %s", __FUNCTION__,
297 av_err2str(err));
298 m_stopped = true;
300 break;
301 }
302 }
303
304 if (audioStreamIdx == packet->stream_index) {
306 usleep(packet->duration * AV_TIME_BASE *
307 av_q2d(format->streams[audioStreamIdx]->time_base));
308 } else {
311 packet = nullptr;
312 }
313 } else if (videoStreamIdx == packet->stream_index) {
315 usleep(packet->duration * AV_TIME_BASE *
316 av_q2d(format->streams[videoStreamIdx]->time_base));
317 } else {
318 packet = nullptr;
319 }
320 } else {
322 packet = nullptr;
323 }
324
325 while (m_paused && !m_stopped)
326 sleep(1);
327
328 if (m_jumpSec && format->pb->seekable) {
329 av_seek_frame(format, format->streams[jumpStreamIdx]->index,
330 packet->pts + (int64_t)(m_jumpSec / // - BufferOffset
331 av_q2d(format->streams[jumpStreamIdx]->time_base)), 0);
332 m_pDevice->Clear();
333 m_jumpSec = 0;
334
335 if (packet) {
337 packet = nullptr;
338 }
339 }
340
341 if (m_stopped) {
342 m_pDevice->Clear();
343 break;
344 }
345 }
346
347 if (packet)
349
350 m_duration = 0;
351 m_currentTime = 0;
352
353 avformat_close_input(&format);
354 avformat_free_context(format);
355}
356
357/*****************************************************************************
358 * cSoftHdControl (cControl mediaplayer)
359 ****************************************************************************/
360
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}
479
Audio and Alsa Interface Header File.
Playlist Entry.
Definition mediaplayer.h:33
std::string m_path
Definition mediaplayer.h:42
std::string m_file
Definition mediaplayer.h:43
std::string m_folder
Definition mediaplayer.h:45
std::string m_subFolder
Definition mediaplayer.h:44
std::string GetPath(void)
Definition mediaplayer.h:40
cPlaylistEntry * GetNextEntry(void)
Definition mediaplayer.h:38
Media Player Control.
static cSoftHdControl * Control()
cSoftHdDevice * m_pDevice
cSkinDisplayReplay * m_pOsd
Output Device Implementation.
static cSoftHdMenu * Menu()
Definition softhdmenu.h:41
Media Player.
Definition mediaplayer.h:54
std::atomic< bool > m_stopped
Definition mediaplayer.h:90
char * m_pSource
Definition mediaplayer.h:84
std::atomic< int > m_jumpSec
Definition mediaplayer.h:88
cPlaylistEntry * m_pFirstEntry
Definition mediaplayer.h:81
std::atomic< bool > m_random
Definition mediaplayer.h:91
cPlaylistEntry * m_pCurrentEntry
Definition mediaplayer.h:82
cSoftHdAudio * m_pAudio
Definition mediaplayer.h:87
std::atomic< bool > m_paused
Definition mediaplayer.h:89
cSoftHdDevice * m_pDevice
Definition mediaplayer.h:86
int64_t GetHardwareOutputPtsMs(void)
Get the hardware output PTS in milliseconds.
Definition audio.cpp:923
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.
virtual eOSState ProcessKey(eKeys)
Handle a key event.
cSoftHdControl(const char *, cSoftHdDevice *)
Create a new control interface and corresponding player.
virtual void Action(void)
Main thread action which invokes replay start.
virtual ~cSoftHdPlayer()
void ReadPlaylist(const char *)
Read the playlist file.
std::string OsdItemString(void)
Compose a full-path-string for the OSD entry.
static bool IsM3UPlaylist(char *source)
Returns true, if the playlist is a m3u playlist.
virtual void Activate(bool On)
Start player thread.
void ShowProgress()
Open the replay OSD.
static cSoftHdPlayer * m_pPlayer
static cSoftHdControl * m_pControl
cPlaylistEntry(std::string)
Builds the playlist entry from a file name.
cSoftHdPlayer(const char *, cSoftHdDevice *)
Create a new player for a file or playlist.
virtual void Hide(void)
Close the replay OSD.
void SetEntry(int)
Set the current entry to play.
virtual ~cSoftHdControl()
void Play(const char *)
Play a file.
#define LOGDEBUG2
log to LOG_DEBUG and add a prefix
Definition logger.h:42
#define LOGERROR
log to LOG_ERR
Definition logger.h:34
#define AV_NOPTS_VALUE
Definition misc.h:74
#define LOGFATAL
log to LOG_ERR and abort
Definition logger.h:32
#define av_err2str(err)
Definition misc.h:112
@ L_MEDIA
mediaplayer logs
Definition logger.h:59
Logger Header File.
Mediaplayer Header File.
Misc Functions.
Output Device Header File.
Plugin Main Menu Header File.