vdr-plugin-softhddevice-drm-gles 1.5.9-20e15de
mediaplayer.cpp
Go to the documentation of this file.
1
25#include <cstdlib>
26#include <fstream>
27#include <string>
28
29extern "C" {
30#include <libavcodec/avcodec.h>
31#include <libavformat/avformat.h>
32}
33
34#include <vdr/player.h>
35
36#include "audio.h"
37#include "logger.h"
38#include "misc.h"
39#include "mediaplayer.h"
40#include "softhddevice.h"
41#include "softhdmenu.h"
42
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
81static bool IsM3UPlaylist(char *source)
82{
83 return (strcasestr(source, ".M3U") && !strcasestr(source, ".M3U8"));
84}
85
93 : cPlayer(pmAudioVideo),
94 m_pDevice(device),
95 m_pAudio(m_pDevice->Audio())
96{
97 m_pSource = (char *) malloc(1 + strlen(url));
98 strcpy(m_pSource, url);
99
103 } else
104 m_pFirstEntry = m_pCurrentEntry = nullptr;
105
106 LOGDEBUG2(L_MEDIA, "mediaplayer: %s: player started", __FUNCTION__);
107}
108
110{
111 m_stopped = true;
112 free(m_pSource);
113
114 while (m_pFirstEntry) {
116 m_pFirstEntry = entry->GetNextEntry();
117 delete entry;
118 m_entries--;
119 }
120
121 LOGDEBUG2(L_MEDIA, "mediaplayer: %s: player stopped", __FUNCTION__);
122}
123
132{
133 LOGDEBUG2(L_MEDIA, "mediaplayer: %s: %s", __FUNCTION__, on ? "On" : "Off");
134 if (on)
135 Start();
136}
137
143{
144 LOGDEBUG2(L_MEDIA, "mediaplayer: %s:", __FUNCTION__);
145 m_noModify = false;
146
148 while(m_pCurrentEntry) {
149 m_jumpSec = 0;
150 Play(m_pCurrentEntry->GetPath().c_str());
151
152 if (!m_noModify) {
154
155 if (m_random) {
156 srand (time (NULL));
157 SetEntry(std::rand() % (m_entries));
158 }
159 }
160 m_noModify = 0;
161
162 if (cSoftHdMenu::Menu())
164 }
165 } else
167
169 usleep(5000);
170
172}
173
177void cSoftHdPlayer::ReadPlaylist(const char *playlist)
178{
179 std::ifstream inputFile;
180 cPlaylistEntry *lastEntry = nullptr;
181 m_entries = 0;
182
183 inputFile.open(playlist);
184 if (!inputFile.good()) {
185 LOGERROR("mediaplayer: %s: open PL %s failed", __FUNCTION__, playlist);
186 return;
187 }
188
189 while (!inputFile.eof()) {
190 std::string s;
191 getline(inputFile, s);
192 if (s.size() && s.compare(0, 1, "#")) {
193 cPlaylistEntry *entry = new cPlaylistEntry(s);
194
195 if (!lastEntry)
196 m_pFirstEntry = entry;
197 else
198 lastEntry->SetNextEntry(entry);
199
200 lastEntry = entry;
201 m_entries++;
202 }
203 }
204
205 inputFile.close();
206}
207
214{
215 cPlaylistEntry *entry;
216 entry = m_pFirstEntry;
217
218 for (int i = 0; i < index ; i++) {
219 entry = entry->GetNextEntry();
220 }
221
222 m_pCurrentEntry = entry;
223 m_noModify = true;
224 m_stopped = true;
225}
226
232void cSoftHdPlayer::Play(const char *url)
233{
234#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(59,0,100)
235 AVCodec *videoCodec;
236#else
237 const AVCodec *videoCodec;
238#endif
239 int err = 0;
240 int audioStreamIdx = 0;
241 int videoStreamIdx;
242 int jumpStreamIdx = 0;
243 int startTime;
244
245 m_stopped = false;
246 m_jumpSec = 0;
247
248 AVFormatContext *format = avformat_alloc_context();
249 if (avformat_open_input(&format, url, NULL, NULL) != 0) {
250 LOGERROR("mediaplayer: %s: Could not open file '%s'", __FUNCTION__, url);
251 return;
252 }
253#ifdef MEDIA_DEBUG
254 av_dump_format(format, -1, url, 0);
255#endif
256 if (avformat_find_stream_info(format, NULL) < 0) {
257 LOGERROR("mediaplayer: %s: Could not retrieve stream info from file '%s'", __FUNCTION__, url);
258 return;
259 }
260
261 for (unsigned int i = 0; i < format->nb_streams; i++) {
262 if (format->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
263 m_pDevice->SetAudioCodec(format->streams[i]->codecpar->codec_id,
264 format->streams[i]->codecpar, format->streams[i]->time_base);
265 audioStreamIdx = jumpStreamIdx = i;
266 break;
267 }
268 }
269
270 videoStreamIdx = av_find_best_stream(format, AVMEDIA_TYPE_VIDEO, -1, -1, &videoCodec, 0);
271
272 if (videoStreamIdx < 0) {
273 LOGDEBUG2(L_MEDIA, "mediaplayer: %s: stream does not seem to contain video", __FUNCTION__);
274 } else {
275 m_pDevice->SetVideoCodec(videoCodec->id,
276 format->streams[videoStreamIdx]->codecpar,
277 format->streams[videoStreamIdx]->time_base);
278 jumpStreamIdx = videoStreamIdx;
279 }
280
281 m_duration = format->duration / AV_TIME_BASE;
282 startTime = format->start_time / AV_TIME_BASE;
283
284 AVPacket *packet = nullptr;
285 while (!m_stopped) {
286 if (!packet) {
287 packet = av_packet_alloc();
288 if (!packet) {
289 LOGFATAL("mediaplayer: %s: out of memory", __FUNCTION__);
290 return;
291 }
292
293 err = av_read_frame(format, packet);
294 if (err < 0) {
295 LOGDEBUG2(L_MEDIA, "mediaplayer: %s: av_read_frame error: %s", __FUNCTION__,
296 av_err2str(err));
297 m_stopped = true;
298 av_packet_free(&packet);
299 break;
300 }
301 }
302
303 if (audioStreamIdx == packet->stream_index) {
304 if (!m_pDevice->PlayAudioPkts(packet)) {
305 usleep(packet->duration * AV_TIME_BASE *
306 av_q2d(format->streams[audioStreamIdx]->time_base));
307 } else {
308 m_currentTime = m_pAudio->GetHardwareOutputPtsMs() / 1000 - startTime;
309 av_packet_free(&packet);
310 packet = nullptr;
311 }
312 } else if (videoStreamIdx == packet->stream_index) {
313 if (!m_pDevice->PlayVideoPkts(packet)) {
314 usleep(packet->duration * AV_TIME_BASE *
315 av_q2d(format->streams[videoStreamIdx]->time_base));
316 } else {
317 packet = nullptr;
318 }
319 } else {
320 av_packet_free(&packet);
321 packet = nullptr;
322 }
323
324 while (m_paused && !m_stopped)
325 sleep(1);
326
327 if (m_jumpSec && format->pb->seekable) {
328 av_seek_frame(format, format->streams[jumpStreamIdx]->index,
329 packet->pts + (int64_t)(m_jumpSec / // - BufferOffset
330 av_q2d(format->streams[jumpStreamIdx]->time_base)), 0);
331 m_pDevice->Clear();
332 m_jumpSec = 0;
333
334 if (packet) {
335 av_packet_free(&packet);
336 packet = nullptr;
337 }
338 }
339
340 if (m_stopped) {
341 m_pDevice->Clear();
342 break;
343 }
344 }
345
346 if (packet)
347 av_packet_free(&packet);
348
349 m_duration = 0;
350 m_currentTime = 0;
351
352 avformat_close_input(&format);
353 avformat_free_context(format);
354}
355
356/*****************************************************************************
357 * cSoftHdControl (cControl mediaplayer)
358 ****************************************************************************/
359
362
370 : cControl(m_pPlayer = new cSoftHdPlayer(url, device)),
371 m_pDevice(device)
372{
373 m_pControl = this;
374}
375
377{
378 delete m_pPlayer;
379 m_pPlayer = NULL;
380 m_pControl = NULL;
381}
382
387{
388 LOGDEBUG2(L_MEDIA, "mediaplayer: %s:", __FUNCTION__);
389 if (m_pOsd)
390 delete m_pOsd;
391
392 m_pOsd = NULL;
393}
394
399{
400 if (!m_pOsd) {
401 LOGDEBUG2(L_MEDIA, "mediaplayer: %s: get OSD", __FUNCTION__);
402 m_pOsd = Skins.Current()->DisplayReplay(false);
403 }
404
407 m_pOsd->SetCurrent(IndexToHMSF(m_pPlayer->GetCurrentTime(), false, 1));
408 m_pOsd->SetTotal(IndexToHMSF(m_pPlayer->GetDuration(), false, 1));
409
410 Skins.Flush();
411}
412
418eOSState cSoftHdControl::ProcessKey(eKeys key)
419{
420 switch (key) {
421 case kNone:
422 if (m_pOsd)
423 ShowProgress();
424 if (m_closing) {
425 Hide();
426 return osStopReplay;
427 }
428 break;
429 case kOk:
430 if (m_pOsd)
431 Hide();
432 else
433 ShowProgress();
434 break;
435 case kPlay:
436 case kUp:
437 if (m_pPlayer->IsPaused()) {
438 m_pPlayer->Pause(false);
439 m_pDevice->Play();
440 }
441 break;
442 case kGreen:
443 m_pPlayer->JumpSec(-60);
444 break;
445 case kYellow:
446 m_pPlayer->JumpSec(60);
447 break;
448 case kLeft:
449 m_pPlayer->JumpSec(-5);
450 break;
451 case kRight:
452 m_pPlayer->JumpSec(5);
453 break;
454 case kBlue:
455 case kBack:
456 Hide();
457 m_pPlayer->Stop();
458 return osStopReplay;
459 case kPause:
460 case kDown:
461 if (m_pPlayer->IsPaused()) {
462 m_pPlayer->Pause(false);
463 m_pDevice->Play();
464 } else {
465 m_pPlayer->Pause(true);
466 m_pDevice->Freeze();
467 }
468 break;
469 case kNext:
470 m_pPlayer->Stop();
471 break;
472 default:
473 break;
474 }
475
476 return osContinue;
477}
Audio and alsa module header file.
std::string m_path
Definition mediaplayer.h:47
std::string m_file
Definition mediaplayer.h:48
std::string m_folder
Definition mediaplayer.h:50
std::string m_subFolder
Definition mediaplayer.h:49
std::string OsdItemString(void)
Compose a full-path-string for the OSD entry.
std::string GetPath(void)
Definition mediaplayer.h:45
void SetNextEntry(cPlaylistEntry *entry)
Definition mediaplayer.h:44
cPlaylistEntry * GetNextEntry(void)
Definition mediaplayer.h:43
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:888
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
void Close(void)
cSkinDisplayReplay * m_pOsd
void ShowProgress()
Open the replay OSD.
static cSoftHdPlayer * m_pPlayer
static cSoftHdControl * m_pControl
virtual void Hide(void)
Close the replay OSD.
virtual ~cSoftHdControl()
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.
void PlayListMenu(void)
Create mediaplayer playlist menu.
static cSoftHdMenu * Menu()
Definition softhdmenu.h:46
std::atomic< bool > m_stopped
Definition mediaplayer.h:96
bool IsPaused(void)
Definition mediaplayer.h:70
char * m_pSource
Definition mediaplayer.h:90
virtual void Action(void)
Main thread action which invokes replay start.
virtual ~cSoftHdPlayer()
void JumpSec(int seconds)
Definition mediaplayer.h:68
std::atomic< int > m_jumpSec
Definition mediaplayer.h:94
cPlaylistEntry * m_pFirstEntry
Definition mediaplayer.h:87
std::atomic< bool > m_random
Definition mediaplayer.h:97
int GetDuration(void)
Definition mediaplayer.h:75
void Pause(bool pause)
Definition mediaplayer.h:69
void ReadPlaylist(const char *)
Read the playlist file.
const char * GetSource(void)
Definition mediaplayer.h:66
cPlaylistEntry * m_pCurrentEntry
Definition mediaplayer.h:88
void Stop(void)
Definition mediaplayer.h:71
virtual void Activate(bool On)
Start player thread.
cSoftHdAudio * m_pAudio
Definition mediaplayer.h:93
std::atomic< bool > m_paused
Definition mediaplayer.h:95
cPlaylistEntry * GetCurrentPlaylistEntry(void)
Definition mediaplayer.h:77
cSoftHdDevice * m_pDevice
Definition mediaplayer.h:92
cSoftHdPlayer(const char *, cSoftHdDevice *)
Create a new player for a file or playlist.
void SetEntry(int)
Set the current entry to play.
int GetCurrentTime(void)
Definition mediaplayer.h:74
void Play(const char *)
Play a file.
Logger class header file.
#define LOGDEBUG2
Definition logger.h:45
#define LOGERROR
Definition logger.h:41
#define LOGFATAL
Logger macros.
Definition logger.h:40
#define L_MEDIA
Definition logger.h:61
static bool IsM3UPlaylist(char *source)
Returns true, if the playlist is a m3u playlist.
Mediaplayer class header file.
Misc function header file.
#define AV_NOPTS_VALUE
Definition misc.h:69
Device class header file.
Softhddevice menu class header file.