source: titan/titan/player.h @ 44948

Last change on this file since 44948 was 44948, checked in by obi, 2 years ago

cleanup

File size: 99.1 KB
Line 
1#ifndef PLAYER_H
2#define PLAYER_H
3
4// playercan bits:
5// 0 policy
6// 1 auditraklist
7// 2 subtitle
8// 3 videomode
9// 4 powerofftimer
10// 5 videosettings
11// 6 stop
12// 7 ff
13// 8 fr
14// 9 pause
15// 10 play
16// 11 jump/seek reverse
17// 12 jump/seek forward
18// 13 changecodec
19// 14 infobar
20// 15 slowmotion
21
22#ifdef EPLAYER3
23Context_t * player = NULL;
24extern OutputHandler_t OutputHandler;
25extern PlaybackHandler_t PlaybackHandler;
26extern ContainerHandler_t ContainerHandler;
27extern ManagerHandler_t ManagerHandler;
28
29#ifdef EXTEPLAYER3
30#include <stdlib.h>
31#include <stdio.h>
32#include <string.h>
33#include <fcntl.h>
34#include <unistd.h>
35#include <sched.h>
36#include <signal.h>
37#ifdef OEBUILD
38#include <inttypes.h>
39#include <stdarg.h>
40#endif
41#include <sys/ioctl.h>
42#include <sys/prctl.h>
43#include <sys/types.h>
44#include <sys/stat.h>
45#include <sys/time.h>
46#include <sys/resource.h>
47#include <sys/mman.h>
48#ifdef OEBUILD
49#include <sys/socket.h>
50#include <sys/un.h>
51#include <errno.h>
52#include <pthread.h>
53#endif
54#include "common.h"
55#ifdef OEBUILD
56//#include "misc.h"
57#endif
58extern int ffmpeg_av_dict_set(const char *key, const char *value, int flags);
59extern void       aac_software_decoder_set(const int32_t val);
60extern void  aac_latm_software_decoder_set(const int32_t val);
61extern void       dts_software_decoder_set(const int32_t val);
62extern void       wma_software_decoder_set(const int32_t val);
63extern void       ac3_software_decoder_set(const int32_t val);
64extern void      eac3_software_decoder_set(const int32_t val);
65extern void       mp3_software_decoder_set(const int32_t val);
66#ifdef OEBUILD1
67extern void       amr_software_decoder_set(const int32_t val);
68extern void    vorbis_software_decoder_set(const int32_t val);
69extern void      opus_software_decoder_set(const int32_t val);
70#endif
71extern void            rtmp_proto_impl_set(const int32_t val);
72extern void        flv2mpeg4_converter_set(const int32_t val);
73#ifdef OEBUILD1
74extern void        sel_program_id_set(const int32_t val);
75#endif
76extern void pcm_resampling_set(int32_t val);
77extern void stereo_software_decoder_set(int32_t val);
78extern void insert_pcm_as_lpcm_set(int32_t val);
79extern void progressive_playback_set(int32_t val);
80
81static void SetBuffering()
82{
83    static char buff[2048];
84    memset( buff, '\0', sizeof(buff));
85    if( setvbuf(stderr, buff, _IOLBF, sizeof(buff)) )
86    {
87        printf("SetBuffering: failed to change the buffer of stderr\n");
88    }
89   
90    // make fgets not blocking
91    int flags = fcntl(stdin->_fileno, F_GETFL, 0);
92    fcntl(stdin->_fileno, F_SETFL, flags | O_NONBLOCK);
93}
94
95/*
96static void SetNice(int prio)
97{
98#if 0
99    setpriority(PRIO_PROCESS, 0, -8);
100   
101    int prio = sched_get_priority_max(SCHED_RR) / 2;
102    struct sched_param param = {
103        .sched_priority = prio
104    };
105    sched_setscheduler(0, SCHED_RR, &param);
106#else
107    int prevPrio = getpriority(PRIO_PROCESS, 0);
108    if (-1 == setpriority(PRIO_PROCESS, 0, prio))
109    {
110        printf("setpriority - failed\n");
111    }
112#endif
113}
114*/
115
116static int HandleTracks(const Manager_t *ptrManager, const PlaybackCmd_t playbackSwitchCmd, const char *argvBuff)
117{
118    int commandRetVal = 0;
119   
120    if (NULL == ptrManager || NULL == argvBuff || 2 != strnlen(argvBuff, 2))
121    {
122        return -1;
123    }
124   
125    switch (argvBuff[1])
126    {
127        case 'l':
128        {
129            TrackDescription_t *TrackList = NULL;
130            ptrManager->Command(player, MANAGER_LIST, &TrackList);
131            if( NULL != TrackList)
132            {
133                int i = 0;
134#ifdef OEBUILD
135//                E2iStartMsg();
136//                E2iSendMsg("{\"%c_%c\": [", argvBuff[0], argvBuff[1]);
137                fprintf(stderr, "{\"%c_%c\": [", argvBuff[0], argvBuff[1]);
138#else
139                fprintf(stderr, "{\"%c_%c\": [", argvBuff[0], argvBuff[1]);
140#endif
141                for (i = 0; TrackList[i].Id >= 0; ++i)
142                {
143                    if(0 < i)
144                    {
145#ifdef OEBUILD
146                        E2iSendMsg(", ");
147#else
148                        fprintf(stderr, ", ");
149#endif
150                    }
151#ifdef OEBUILD
152//                   E2iSendMsg("{\"id\":%d,\"e\":\"%s\",\"n\":\"%s\"}", TrackList[i].Id , TrackList[i].Encoding, TrackList[i].Name);
153                    fprintf(stderr, "{\"%c_%c\": [", argvBuff[0], argvBuff[1]);
154#else
155                    fprintf(stderr, "{\"%c_%c\": [", argvBuff[0], argvBuff[1]);
156#endif
157                    free(TrackList[i].Encoding);
158                    free(TrackList[i].Name);
159                }
160                E2iSendMsg("]}\n");
161                E2iEndMsg();
162                free(TrackList);
163            }
164            else
165            {
166                // not tracks
167#ifdef OEBUILD
168//                E2iSendMsg("{\"%c_%c\": []}\n", argvBuff[0], argvBuff[1]);
169                fprintf(stderr, "{\"%c_%c\": []}\n", argvBuff[0], argvBuff[1]);
170#else
171                fprintf(stderr, "{\"%c_%c\": []}\n", argvBuff[0], argvBuff[1]);
172#endif
173            }
174            break;
175        }
176        case 'c':
177        {
178           
179            TrackDescription_t *track = NULL;
180            ptrManager->Command(player, MANAGER_GET_TRACK_DESC, &track);
181            if (NULL != track)
182            {
183                if ('a' == argvBuff[0] || 's' == argvBuff[0])
184                {
185#ifdef OEBUILD
186//                    E2iSendMsg("{\"%c_%c\":{\"id\":%d,\"e\":\"%s\",\"n\":\"%s\"}}\n", argvBuff[0], argvBuff[1], track->Id , track->Encoding, track->Name);
187                    fprintf(stderr, "{\"%c_%c\":{\"id\":%d,\"e\":\"%s\",\"n\":\"%s\"}}\n", argvBuff[0], argvBuff[1], track->Id , track->Encoding, track->Name);
188#else
189                    fprintf(stderr, "{\"%c_%c\":{\"id\":%d,\"e\":\"%s\",\"n\":\"%s\"}}\n", argvBuff[0], argvBuff[1], track->Id , track->Encoding, track->Name);
190#endif
191                }
192                else // video
193                {
194#ifdef OEBUILD
195//                    E2iSendMsg("{\"%c_%c\":{\"id\":%d,\"e\":\"%s\",\"n\":\"%s\",\"w\":%d,\"h\":%d,\"f\":%u,\"p\":%d,\"an\":%d,\"ad\":%d}}\n", \
196//                    argvBuff[0], argvBuff[1], track->Id , track->Encoding, track->Name, track->width, track->height, track->frame_rate, track->progressive, track->aspect_ratio_num, track->aspect_ratio_den);
197                    fprintf(stderr, "{\"%c_%c\":{\"id\":%d,\"e\":\"%s\",\"n\":\"%s\",\"w\":%d,\"h\":%d,\"f\":%u,\"p\":%d,\"an\":%d,\"ad\":%d}}\n", \
198                    argvBuff[0], argvBuff[1], track->Id , track->Encoding, track->Name, track->width, track->height, track->frame_rate, track->progressive, track->aspect_ratio_num, track->aspect_ratio_den);
199#else
200                    fprintf(stderr, "{\"%c_%c\":{\"id\":%d,\"e\":\"%s\",\"n\":\"%s\",\"w\":%d,\"h\":%d,\"f\":%u,\"p\":%d,\"an\":%d,\"ad\":%d}}\n", \
201                    argvBuff[0], argvBuff[1], track->Id , track->Encoding, track->Name, track->width, track->height, track->frame_rate, track->progressive, track->aspect_ratio_num, track->aspect_ratio_den);
202#endif
203                }
204                free(track->Encoding);
205                free(track->Name);
206                free(track);
207            }
208            else
209            {
210                // no tracks
211                if ('a' == argvBuff[0] || 's' == argvBuff[0])
212                {
213#ifdef OEBUILD
214//                    E2iSendMsg("{\"%c_%c\":{\"id\":%d,\"e\":\"%s\",\"n\":\"%s\"}}\n", argvBuff[0], argvBuff[1], -1, "", "");
215                    fprintf(stderr, "{\"%c_%c\":{\"id\":%d,\"e\":\"%s\",\"n\":\"%s\"}}\n", argvBuff[0], argvBuff[1], -1, "", "");
216#else
217                    fprintf(stderr, "{\"%c_%c\":{\"id\":%d,\"e\":\"%s\",\"n\":\"%s\"}}\n", argvBuff[0], argvBuff[1], -1, "", "");
218#endif
219                }
220                else // video
221                {
222#ifdef OEBUILD
223//                    E2iSendMsg("{\"%c_%c\":{\"id\":%d,\"e\":\"%s\",\"n\":\"%s\",\"w\":%d,\"h\":%d,\"f\":%u,\"p\":%d}}\n", argvBuff[0], argvBuff[1], -1, "", "", -1, -1, 0, -1);
224                    fprintf(stderr, "{\"%c_%c\":{\"id\":%d,\"e\":\"%s\",\"n\":\"%s\",\"w\":%d,\"h\":%d,\"f\":%u,\"p\":%d}}\n", argvBuff[0], argvBuff[1], -1, "", "", -1, -1, 0, -1);
225#else
226                    fprintf(stderr, "{\"%c_%c\":{\"id\":%d,\"e\":\"%s\",\"n\":\"%s\",\"w\":%d,\"h\":%d,\"f\":%u,\"p\":%d}}\n", argvBuff[0], argvBuff[1], -1, "", "", -1, -1, 0, -1);
227#endif
228                }
229            }
230            break;
231        }
232        default:
233        {
234            /* switch command available only for audio and subtitle tracks */
235            if ('a' == argvBuff[0] || 's' == argvBuff[0])
236            {
237                int ok = 0;
238                int id = -1;
239                if ('i' == argvBuff[1])
240                {
241                    int idx = -1;
242                    ok = sscanf(argvBuff+2, "%d", &idx);
243                    if (idx >= 0)
244                    {
245                        TrackDescription_t *TrackList = NULL;
246                        ptrManager->Command(player, MANAGER_LIST, &TrackList);
247                        if( NULL != TrackList)
248                        {
249                            int i = 0;
250                            for (i = 0; TrackList[i].Id >= 0; ++i)
251                            {
252                                if (idx == i)
253                                {
254                                    id = TrackList[i].Id;
255                                }
256                                free(TrackList[i].Encoding);
257                                free(TrackList[i].Name);
258                            }
259                            free(TrackList);
260                        }
261                    }
262                    else
263                    {
264                        id = idx;
265                    }
266                }
267                else
268                {
269                    ok = sscanf(argvBuff+1, "%d", &id);
270                }
271               
272                if(id >= 0 || (1 == ok && id == -1))
273                {
274                    commandRetVal = player->playback->Command(player, playbackSwitchCmd, (void*)&id);
275#ifdef OEBUILD
276//                    E2iSendMsg("{\"%c_%c\":{\"id\":%d,\"sts\":%d}}\n", argvBuff[0], 's', id, commandRetVal);
277                    fprintf(stderr, "{\"%c_%c\":{\"id\":%d,\"sts\":%d}}\n", argvBuff[0], 's', id, commandRetVal);
278#else
279                    fprintf(stderr, "{\"%c_%c\":{\"id\":%d,\"sts\":%d}}\n", argvBuff[0], 's', id, commandRetVal);
280#endif
281                }
282            }
283            break;
284        }
285    }
286   
287    return commandRetVal;
288}
289
290
291static void UpdateVideoTrack()
292{
293    HandleTracks(player->manager->video, (PlaybackCmd_t)-1, "vc");
294}
295#endif
296#endif
297
298#ifdef EPLAYER4
299//#define GST_VERSION_MAJOR (0)
300GstElement *pipeline = NULL;
301gint m_framerate;
302unsigned long long m_gst_startpts = 0;
303CustomData data;
304GstElement *video_sink = NULL;
305struct stimerthread* subtitlethread = NULL;
306uint32_t buf_pos_ms = 0;
307uint32_t duration_ms = 0;
308int subtitleflag = 0;
309char *subtext = NULL;
310#else
311struct stimerthread* subtitlethread = NULL;
312#endif
313
314//titan player
315
316//flag 0: from play
317//flag 1: from timeshift
318//flag 2: from playrcjumpr
319int playerstartts(char* file, int flag)
320{
321        int fd = -1, ret = 0, tssize = 188;
322        int16_t pmtpid = 0;
323        int serviceid = 0;
324        int supermagic = -1;
325        int lastpos = 0;
326        struct channel* chnode = NULL;
327        struct service* snode = NULL;
328        struct dvbdev* fenode = NULL;
329        struct dvbdev* dvrnode = NULL;
330        status.prefillbuffer = 0;
331#ifdef EPLAYER4
332        status.bufferpercent = 0;
333#endif
334        //supermagic = getsupermagic(file);
335        printf("player--> playerstartts flag:%i\n", flag);
336        addconfig("lastplayertype", "1");
337
338        if(supermagic == NFS_SUPER_MAGIC || supermagic == SMB_SUPER_MAGIC)
339        {
340                debug(150, "use O_DIRECT to open file %s", file);
341                fd = open(file, O_RDONLY | O_LARGEFILE | O_NONBLOCK | O_DIRECT);
342        }
343        else
344                fd = open(file, O_RDONLY | O_LARGEFILE | O_NONBLOCK);
345
346        if(fd < 0)
347        {
348                perr("open player file");
349                return 1;
350        }
351
352        fenode = fegetdummy();
353        dvrnode = dvropen(fenode);
354        if(dvrnode == NULL)
355        {
356                err("find dvr dev");
357                close(fd);
358                return 1;
359        }
360        printf("player-> dvrnode: %i:%i\n", dvrnode->devnr, dvrnode->adapter);
361        if(flag == 0 || flag == 2)
362        {
363                //TODO: funktion to get tssize from file content
364                if(cmpfilenameext(file, ".mts") == 0) tssize = 192;
365                if(cmpfilenameext(file, ".m2ts") == 0) tssize = 192;
366               
367                ret = dvbfindpmtpid(fd, &pmtpid, &serviceid, tssize);
368                if(ret == 1)
369                {
370                        err("find sid/pmt pid");
371                        close(fd);
372                        dvrclose(dvrnode, -1);
373                        return 1;
374                }
375               
376                lastpos = 0;
377                if(flag == 0 && getconfigint("showlastpos", NULL) == 1)
378                {
379                        char* fileseek = changefilenameext(file, ".se");
380                        FILE* fbseek = fopen(fileseek, "r");
381                        if(fbseek != NULL)
382                        {
383                                ret = textbox(_("Message"), _("Start at last position ?"), _("OK"), getrcconfigint("rcok", NULL), _("EXIT"), getrcconfigint("rcexit", NULL), NULL, 0, NULL, 0, 1000, 200, 10, 0);
384                                if(ret == 0 || ret == 1)
385                                {
386                                        char* skip1 = calloc(1, 20);
387                                        if(skip1 != NULL)
388                                        {
389                                                fscanf(fbseek, "%s", skip1);
390                                                off64_t seekpos = atoll(skip1);
391                                                seekpos = seekpos - (seekpos % tssize);
392                                                lseek64(fd, atoll(skip1), SEEK_SET);
393                                                lastpos = 1;
394                                        }
395                                        free(skip1); skip1 = NULL;
396                                }
397                                fclose(fbseek);
398                        }
399                        free(fileseek); fileseek = NULL;
400                }       
401               
402                status.autoseek = 0;
403               
404                if(flag == 0)
405                {
406                        delmarkernode(-1);
407                        char* filemarker = changefilenameext(file, ".ma");
408                        getmarker(filemarker);
409                        free(filemarker); filemarker=NULL;
410                }
411               
412                if(status.playmarker != NULL)
413                {
414                        char* testfile = changefilenameext(file, ".as");
415                        FILE* testseek = fopen(testfile, "r");
416                        if(testseek != NULL)
417                        {
418                                if(lastpos == 0)
419                                        lseek64(fd, status.playmarker->pos, SEEK_SET);
420                                status.autoseek = 2;
421                                addtimer(&markerautoseek_thread, START, 10000, 1, NULL, NULL, NULL);
422                                fclose(testseek);
423                        }
424                        free(testfile); testfile = NULL;
425                }
426                printf("player--> create channel\n");           
427                delchannel(serviceid, 0, 1);
428                chnode = createchannel("player", 0, 0, serviceid, 99, 0, -1, -1, -1, -1, 0, -1);
429                if(chnode != NULL) chnode->pmtpid = pmtpid;
430        }
431        else
432                chnode = status.aktservice->channel;
433
434        if(chnode == NULL)
435        {
436                err("create channel");
437                close(fd);
438                dvrclose(dvrnode, -1);
439                return 1;
440        }
441
442        if(flag == 1)
443        {
444                ret = servicestart(chnode, NULL, NULL, 2);
445                if(ret != 0)
446                {
447                        err("start play");
448                        close(fd);
449                        dvrclose(dvrnode, -1);
450                        return 1;
451                }
452               
453                //on permanent timeshift seek to end, and a little back (eof problem)
454                if(status.timeshifttype == 1)
455                {
456                        if(status.timeshiftpos > 0)
457                                lseek64(fd, status.timeshiftpos, SEEK_SET);
458                        else
459                        {
460                                unsigned long long pos = lseek64(fd, 0, SEEK_END);
461                                pos -= 10000000;
462                                pos = pos - (pos & tssize);
463                                lseek64(fd, -pos, SEEK_END);
464                        }
465                }
466        }
467
468        printf("player--> recordstartreal.. start\n");
469        ret = recordstartreal(NULL, fd, dvrnode->fd, RECPLAY, 0, NULL, tssize);
470        printf("player--> recordstartreal.. stop ret:%i\n",ret);
471        if(ret != 0)
472        {
473                err("start play thread");
474                close(fd);
475                dvrclose(dvrnode, -1);
476                return 1;
477        }
478
479        snode = getservice(RECORDPLAY, 0);
480        if(snode != NULL)
481        {
482                int dupfd = -1;
483                snode->recname = ostrcat(file, NULL, 0, 0);
484
485                dupfd = open(snode->recname, O_RDONLY | O_LARGEFILE);
486                if(dupfd > -1)
487                        gettsinfo(dupfd, &snode->lenpts, &snode->startpts, &snode->endpts, &snode->bitrate, snode->tssize);
488
489                if(flag == 1)
490                {
491                        snode->lenpts = 0;
492                        snode->endpts = 0;
493                }
494                else
495                {
496                        if(getservicebyrecname(file, 1, 0) != NULL) //playfile is recording, so len can change
497                        {
498                                snode->lenpts = 0;
499                                snode->endpts = 0;
500                        }
501                        else if(dupfd > -1)
502                                snode->endoffile = lseek64(dupfd , 0, SEEK_END);
503                }
504                close(dupfd);
505        }
506
507        if(flag == 0 || flag == 2)
508        {
509                ret = servicestart(chnode, NULL, NULL, 1);
510                if(ret != 0)
511                {
512                        err("start play");
513                        if(snode != NULL) snode->recendtime = 1;
514                        close(fd);
515                        dvrclose(dvrnode, -1);
516                        return 1;
517                }
518                //status.playercan = 0x7EFF;
519                status.playercan = 0xFFFF;     
520        }
521
522        return 0;
523}
524
525//flag 0: from play
526//flag 1: from timeshift
527//flag 2: from playrcjumpr/playerafterendts
528//flag1 0: stop from rcstop
529//flag1 1: stop from servicestop
530void playerstopts(int flag, int flag1)
531{
532        int ret = 0;
533        struct service* snode = NULL;
534        struct channel* node = NULL;
535
536        snode = getservice(RECORDPLAY, flag1);
537
538        if(snode != NULL && snode->recsrcfd >= 0 && flag == 0 && flag1 == 0)
539        {
540                char* fileseek = changefilenameext(snode->recname, ".se");
541                FILE* fbseek = fopen(fileseek, "w");
542                if(fbseek != NULL)
543                {
544                        off64_t pos = getcurrentpos(snode);
545                        if(pos <= 0)
546                                pos = lseek64(snode->recsrcfd, 0, SEEK_CUR);
547                        fprintf(fbseek,"%lld", pos);
548                        fclose(fbseek);
549                }
550                free(fileseek); fileseek=NULL;
551                char* filemarker = changefilenameext(snode->recname, ".ma");
552                ret = putmarker(filemarker);
553                free(filemarker); filemarker=NULL;
554                delmarkernode(-1);
555        }
556       
557        if(snode != NULL) snode->recendtime = 1;
558       
559        if(flag == 0 || flag == 2)
560        {
561                playerslowts(0);
562                playerffts(0);
563
564                ret = servicestop(status.aktservice, 1, 1);
565                if(ret == 1)
566                {
567                        debug(150, "can't stop ts playback service");   
568                }
569                else
570                        status.aktservice->channel = NULL;
571
572                               
573                node = gettmpchannel();
574                if(node != NULL && ostrcmp(node->name, "player") == 0)
575                        delchannel(node->serviceid, node->transponderid, 1);
576        }
577}
578
579void playerresetts()
580{
581#ifdef DREAMBOX
582        videofreeze(status.aktservice->videodev);
583        dmxstart(status.aktservice->dmxaudiodev);
584        audioplay(status.aktservice->audiodev);
585        audiopause(status.aktservice->audiodev);
586#else
587        audiostop(status.aktservice->audiodev);
588        videostop(status.aktservice->videodev, 0);
589#endif
590
591#ifdef MIPSEL
592        if(checkbox("DM7020HD") == 0 && checkbox("DM7020HDV2") == 0 && vubox1 == 0)
593        {
594                videoclearbuffer(status.aktservice->videodev);
595                audioclearbuffer(status.aktservice->audiodev);
596        }
597#endif
598
599#ifdef DREAMBOX
600        videoslowmotion(status.aktservice->videodev, 0);
601        videofastforward(status.aktservice->videodev, 0);
602        videocontinue(status.aktservice->videodev);
603        audiocontinue(status.aktservice->audiodev);
604#else
605        videoplay(status.aktservice->videodev);
606        audioplay(status.aktservice->audiodev);
607#endif
608}
609
610void playercontinuets()
611{
612        videocontinue(status.aktservice->videodev);
613#ifdef MIPSEL
614        if(checkchipset("HI3798MV200") == 1 || checkbox("DM7020HD") == 1 || checkbox("DM7020HDV2") == 1 || vubox1 == 1)
615                audioplay(status.aktservice->audiodev);
616        audiocontinue(status.aktservice->audiodev);
617#else
618        audioplay(status.aktservice->audiodev);
619#endif
620}
621
622void playerpausets()
623{
624        videofreeze(status.aktservice->videodev);
625        audiopause(status.aktservice->audiodev);
626}
627
628//flag 0: with lock
629//flag 1: without lock
630int playerseekts(struct service* servicenode, int sekunden, int flag)
631{
632        off64_t offset = 0;
633        off64_t endoffile = 0;
634        off64_t currentpos = 0;
635        //off64_t fdptspos = 0;
636        //int ret = 0;
637        unsigned long long lenpts = 0;
638        unsigned long long startpts = 0;
639        unsigned long long endpts = 0;
640        unsigned long long bitrate = 0;
641        //unsigned long long aktpts = 0;
642        //unsigned long long fdpts = 0;
643        //int aktsekunden = 0;
644        int sekundenoff = 0;
645       
646        if(servicenode == NULL) return 1;
647
648        if(servicenode->recsrcfd < 0)
649        {
650                err("source fd not ok");
651                return 1;
652        }
653       
654        if(flag == 0) m_lock(&status.tsseekmutex, 15);
655
656/*
657        ret = videogetpts(status.aktservice->videodev, &aktpts);
658        if(ret == 0)
659        {
660                aktsekunden = aktpts / 90000;
661        }
662        else
663                aktsekunden = 0;
664        ret = getpts(servicenode->recsrcfd, 0, 0, 256 * 1024, &fdpts, &fdptspos, -1, servicenode->tssize);
665        if(ret == 0 && aktsekunden != 0)
666        {
667                sekundenoff = fdpts / 90000 - aktsekunden ;
668                //currentpos = lseek64(servicenode->recsrcfd, fdptspos, SEEK_SET);
669        }
670        else
671                sekundenoff = 0;
672*/
673       
674        currentpos = lseek64(servicenode->recsrcfd, 0, SEEK_CUR);
675
676        lenpts = servicenode->lenpts;
677        startpts = servicenode->startpts;
678        endpts = servicenode->endpts;
679        bitrate = servicenode->bitrate;
680        if(gettsinfo(servicenode->recsrcfd, &lenpts, &startpts, &endpts, &bitrate, servicenode->tssize) != 0)
681        {
682                err("can't read ts info");
683                lseek64(servicenode->recsrcfd, currentpos, SEEK_SET);
684                if(flag == 0) m_unlock(&status.tsseekmutex, 15);
685                return 1;
686        }
687        playerpausets();
688        if(servicenode->endoffile > 0)
689                endoffile = servicenode->endoffile - (servicenode->tssize * 2);
690        else
691                endoffile = lseek64(servicenode->recsrcfd , -servicenode->tssize * 2, SEEK_END);
692
693/*
694        ret = videoclearbuffer(status.aktservice->videodev);
695        ret = audioclearbuffer(status.aktservice->audiodev);
696        ret = videodiscontinuityskip(status.aktservice->videodev, 0);
697*/
698
699        if(sekunden >= 0)
700        {
701                if(sekundenoff != 0)
702                        offset = (bitrate / 8) * (sekunden - sekundenoff);
703                else
704                        offset = (bitrate / 8) * sekunden - 5000000;
705                offset = offset - (offset % servicenode->tssize);
706                if(currentpos + offset > endoffile)
707                {
708                        offset = endoffile - currentpos;
709                        offset = offset - (offset % servicenode->tssize);
710                }
711        }
712        else
713        {
714                sekunden = sekunden * -1;
715                if(sekundenoff != 0)
716                        offset = (bitrate / 8) * (sekunden + sekundenoff);
717                else
718                        offset = (bitrate / 8) * sekunden;
719                if(offset > 0) offset += 5000000;
720                offset = offset - (offset % servicenode->tssize);
721                if(currentpos - offset < 0)
722                        offset = currentpos;
723                offset = offset * -1;
724        }
725        offset += currentpos;
726        currentpos = lseek64(servicenode->recsrcfd, offset, SEEK_SET);
727       
728        if(checkbox("DM7020HD") != 1 && checkbox("DM7020HDV2") != 1 && vubox1 != 1)
729                playerresetts();
730        else
731        {
732                videoclearbuffer(status.aktservice->videodev);
733                audioclearbuffer(status.aktservice->audiodev);
734        }       
735        playercontinuets();
736
737        if(flag == 0) m_unlock(&status.tsseekmutex, 15);
738        return 0;
739}
740
741void playerffts(int speed)
742{
743#ifdef MIPSEL
744        if(checkbox("DM7020HD") == 1 || checkbox("DM7020HDV2") == 1 || vubox1 == 1)
745        {
746                //audiopause(status.aktservice->audiodev);
747                audiostop(status.aktservice->audiodev);
748                dmxstop(status.aktservice->dmxaudiodev);
749                videoslowmotion(status.aktservice->videodev, 0);
750                videofastforward(status.aktservice->videodev, speed);
751                videocontinue(status.aktservice->videodev);
752                //audiocontinue(status.aktservice->audiodev);
753        }
754        else
755        {
756        audiostop(status.aktservice->audiodev);
757#ifdef DREAMBOX
758        dmxstop(status.aktservice->dmxaudiodev);
759#endif
760
761        videoslowmotion(status.aktservice->videodev, 0);
762        videofastforward(status.aktservice->videodev, speed);
763        videocontinue(status.aktservice->videodev);
764        }
765#else   
766        videofastforward(status.aktservice->videodev, speed);
767#endif
768}
769
770void playerslowts(int speed)
771{
772#ifdef MIPSEL
773        if(checkbox("DM7020HD") == 1 || checkbox("DM7020HDV2") == 1 || vubox1 == 1)
774        {
775                audiostop(status.aktservice->audiodev);
776                dmxstop(status.aktservice->dmxaudiodev);
777                //audiopause(status.aktservice->audiodev);
778                videoslowmotion(status.aktservice->videodev, speed);
779                videofastforward(status.aktservice->videodev, 0);
780                videocontinue(status.aktservice->videodev);
781                //audiocontinue(status.aktservice->audiodev);
782        }
783        else
784        {
785        audiostop(status.aktservice->audiodev);
786       
787#ifdef DREAMBOX
788        dmxstop(status.aktservice->dmxaudiodev);
789#endif 
790
791        videoslowmotion(status.aktservice->videodev, speed);
792        videofastforward(status.aktservice->videodev, 0);
793        videocontinue(status.aktservice->videodev);
794        }
795#else           
796        videoslowmotion(status.aktservice->videodev, speed);
797#endif
798}
799
800//flag = 0 --> recordplay
801//flag = 1 --> timeshift
802void playerfrts(int speed, int flag)
803{
804        if(flag == 1)
805                videocontinue(status.aktservice->videodev);
806        if(speed == -2)
807        {
808                videoclearbuffer(status.aktservice->videodev);
809                audioclearbuffer(status.aktservice->audiodev);
810        }
811        speed *= -1;
812#ifdef MIPSEL
813        if(checkbox("DM7020HD") == 1 || checkbox("DM7020HDV2") == 1 || vubox1 == 1)
814        {
815                //audiopause(status.aktservice->audiodev);
816                audiostop(status.aktservice->audiodev);
817                dmxstop(status.aktservice->dmxaudiodev);
818                videoslowmotion(status.aktservice->videodev, 0);
819                videofastforward(status.aktservice->videodev, speed);
820                videocontinue(status.aktservice->videodev);
821                //audiocontinue(status.aktservice->audiodev);
822        }
823        else
824        {
825        audiostop(status.aktservice->audiodev);
826#ifdef DREAMBOX
827        dmxstop(status.aktservice->dmxaudiodev);
828#endif
829        videoslowmotion(status.aktservice->videodev, 0);
830        videofastforward(status.aktservice->videodev, speed);
831        videocontinue(status.aktservice->videodev);
832        }
833#else   
834        videofastforward(status.aktservice->videodev, speed);
835#endif
836}
837       
838
839//flag = 0 --> play ts
840//flag = 1 --> timeshift
841//flag = 2 --> timeshift, not in play mode (only recording)
842int playergetinfots(unsigned long long* lenpts, unsigned long long* startpts, unsigned long long* endpts, unsigned long long* aktpts, unsigned long long* bitrate, int flag)
843{
844        int ret = 0, dupfd = -1;
845        double ratio = 0;
846        struct service* snode = NULL;
847        unsigned long long lenpts1 = 0;
848        unsigned long long startpts1 = 0;
849        unsigned long long endpts1 = 0;
850        unsigned long long bitrate1 = 0;
851        unsigned long long endoffile1 = 0;
852        unsigned long long aktpos = 0;
853       
854        if(flag == 2)
855                snode = getservice(RECORDTIMESHIFT, 0);
856        else
857                snode = getservice(RECORDPLAY, 0);
858               
859        if(snode == NULL) return 1;
860
861        if(snode->lenpts > 0 && snode->startpts > 0 && snode->endpts > 0 && snode->bitrate > 0 && snode->endoffile > 0)
862        {
863                if(lenpts != NULL) *lenpts = snode->lenpts;
864                if(startpts != NULL) *startpts = snode->startpts;
865                if(endpts != NULL) *endpts = snode->endpts;
866                if(bitrate != NULL) *bitrate = snode->bitrate;
867
868                //ret = videogetpts(status.aktservice->videodev, aktpts);
869                if(aktpts != NULL)
870                {
871                        m_lock(&status.tsseekmutex, 15);
872                        if(flag == 2)
873                                aktpos = lseek64(snode->recdstfd , 0, SEEK_CUR);
874                        else
875                                aktpos = lseek64(snode->recsrcfd , 0, SEEK_CUR);
876                        m_unlock(&status.tsseekmutex, 15);
877
878                        ratio = (double)snode->endoffile / (double)(snode->endpts - snode->startpts);
879                        if(ratio == 0) ratio = 1;
880                        *aktpts = ((double)aktpos / ratio);
881                        *aktpts += snode->startpts;
882                }
883
884                return ret;
885        }
886       
887        dupfd = open(snode->recname, O_RDONLY | O_LARGEFILE);
888        if(dupfd < 0)
889        {
890                err("copy source fd not ok");
891                return 1;
892        }
893
894        lenpts1 = snode->lenpts;
895        startpts1 = snode->startpts;
896        endpts1 = snode->endpts;
897        bitrate1 = snode->bitrate;
898        if(gettsinfo(dupfd, &lenpts1, &startpts1, &endpts1, &bitrate1, snode->tssize) != 0)
899        {
900                err("can't read ts info");
901                return 1;
902        }
903
904        if(lenpts != NULL) *lenpts = lenpts1;
905        if(startpts != NULL) *startpts = startpts1;
906        if(endpts != NULL) *endpts = endpts1;
907        if(bitrate != NULL) *bitrate = bitrate1;
908
909        //ret = videogetpts(status.aktservice->videodev, aktpts);
910        if(aktpts != NULL)
911        {
912                m_lock(&status.tsseekmutex, 15);
913                if(flag == 2)
914                        aktpos = lseek64(snode->recdstfd, 0, SEEK_CUR);
915                else
916                        aktpos = lseek64(snode->recsrcfd, 0, SEEK_CUR);
917                m_unlock(&status.tsseekmutex, 15);
918
919                if(snode->endoffile <= 0)
920                        endoffile1 = lseek64(dupfd, 0, SEEK_END);
921                else
922                        endoffile1 = snode->endoffile;
923
924                if(endpts1 == 0)
925                        ratio = 1;
926                else
927                        ratio = (double)endoffile1 / (double)(endpts1 - startpts1);
928
929                if(ratio == 0) ratio = 1;
930                *aktpts = ((double)aktpos / ratio);
931                *aktpts += startpts1;
932        }
933
934        close(dupfd);
935        return ret;
936}
937
938void playerchangeaudiotrackts()
939{
940        screenaudiotrack();
941}
942
943void playerchangesubtitletrackts()
944{
945        screensubtitle();
946}
947
948int playerisplayingts()
949{
950        struct service* snode = getservice(RECORDPLAY, 0);
951
952        if(snode == NULL)
953                return 0;
954        return 1;
955}
956
957void playerafterendts()
958{
959        playerstopts(2, 0);
960}
961
962#ifdef EPLAYER4
963void playersubtitleclean(char* data, int len)
964{
965        char* zeichen = NULL;
966        int found = 1;
967       
968        while(found == 1)
969        {
970                found = 0;
971                zeichen = NULL;
972                zeichen = strstr(data, "&apos;");
973                if(zeichen != NULL)
974                {
975                        zeichen[0] = '\'';
976                        memcpy(zeichen+1, zeichen+6, len - (zeichen - data + 1));
977                        found = 1;
978                }
979                zeichen = NULL;
980                zeichen = strstr(data, "&amp;");
981                if(zeichen != NULL)
982                {
983                        zeichen[0] = '&';
984                        memcpy(zeichen+1, zeichen+5, len - (zeichen - data + 1));
985                        found = 1;
986                }
987                zeichen = NULL;
988                zeichen = strstr(data, "&quot;");
989                if(zeichen != NULL)
990                {
991                        zeichen[0] = '"';
992                        memcpy(zeichen+1, zeichen+6, len - (zeichen - data + 1));
993                        found = 1;
994                }
995                zeichen = NULL;
996                zeichen = strstr(data, "&lt;");
997                if(zeichen != NULL)
998                {
999                        zeichen[0] = '<';
1000                        memcpy(zeichen+1, zeichen+4, len - (zeichen - data + 1));
1001                        found = 1;
1002                }
1003                zeichen = NULL;
1004                zeichen = strstr(data, "&gt;");
1005                if(zeichen != NULL)
1006                {
1007                        zeichen[0] = '<';
1008                        memcpy(zeichen+1, zeichen+4, len - (zeichen - data + 1));
1009                        found = 1;
1010                }
1011                //workaround da keine Aufbereitung
1012                zeichen = NULL;
1013                zeichen = strstr(data, "<i>");
1014                if(zeichen != NULL)
1015                {
1016                        memcpy(zeichen, zeichen+3, len - (zeichen - data + 1));
1017                        found = 1;
1018                }
1019                zeichen = NULL;
1020                zeichen = strstr(data, "</i>");
1021                if(zeichen != NULL)
1022                {
1023                        memcpy(zeichen, zeichen+4, len - (zeichen - data + 1));
1024                        found = 1;
1025                }
1026        }
1027}
1028#endif
1029
1030#ifdef EPLAYER4
1031void playersubtitle_thread()
1032{
1033        struct skin* framebuffer = getscreen("framebuffer");
1034        struct skin* subtitle = getscreen("gstsubtitle");
1035        char* bg = NULL;
1036        int count = 0;
1037       
1038        subtitle->bgcol = -1;
1039       
1040        setnodeattr(subtitle, framebuffer, 0);
1041        bg = savescreen(subtitle);
1042       
1043        while(subtitlethread->aktion != STOP)
1044        {
1045                if(duration_ms != 0)
1046                {
1047                        count = 0;
1048                        changetext(subtitle, subtext);
1049                        count = duration_ms / 100;
1050                        drawscreen(subtitle, 0, 0);
1051                        while(count > 0 && subtitlethread->aktion != STOP)
1052                        {
1053                                usleep(100000);
1054                                count = count - 1;
1055                        }
1056                        changetext(subtitle, " ");
1057                        drawscreen(subtitle, 0, 0);
1058                        duration_ms = 0;
1059                }
1060                else
1061                        usleep(100000);
1062        }
1063        free(subtext); subtext = NULL;
1064        restorescreen(bg, subtitle);
1065        blitfb(0);
1066        subtitlethread = NULL;
1067}
1068#else
1069void playersubtitle_thread(struct stimerthread* timernode, char* input, int flag)
1070{
1071        uint32_t sub_duration_ms = 0;
1072        uint32_t sub_pts_ms = 0;
1073        char *sub_text = NULL;
1074        int sub_pts_sec = 0;
1075        int sub_duration_sec = 0;
1076
1077        char* sub_duration = oregex(".*duration=(.*);pts=.*", input);
1078
1079        if(sub_duration != NULL)
1080        {
1081                sub_duration_ms = atoi(sub_duration);
1082                sub_duration_sec = sub_duration_ms / 1000 + 1;
1083        }
1084
1085        char* sub_pts = oregex(".*;pts=(.*);trackid=.*", input);
1086
1087        if(sub_pts != NULL)
1088        {
1089                sub_pts_ms = atoi(sub_pts);
1090                sub_pts_sec = sub_pts_ms / 90000;
1091        }
1092
1093
1094        char* sub_trackid = oregex(".*;trackid=(.*);subtext.*", input);
1095        sub_text = oregex(".*;subtext=(.*).*", input);
1096
1097        struct skin* framebuffer = getscreen("framebuffer");
1098        struct skin* subtitle = getscreen("gstsubtitle");
1099        char* bg = NULL;
1100        int count = 0;
1101
1102        subtitle->bgcol = -1;
1103
1104        setnodeattr(subtitle, framebuffer, 0);
1105        bg = savescreen(subtitle);
1106
1107        while(subtitlethread->aktion != STOP)
1108        {
1109                if(sub_duration_ms != 0)
1110                {
1111                        int64_t pts = 0;
1112                        int sec = 0;
1113
1114                        if(player && player->playback)
1115                        {
1116                                player->playback->Command(player, PLAYBACK_PTS, &pts);
1117                                sec = pts / 90000;
1118                        }
1119
1120                        while(sec < sub_pts_sec && subtitlethread->aktion != STOP)
1121                        {
1122                                sleep(1);
1123                                sec++;
1124                        }
1125
1126                        count = 0;
1127                        changetext(subtitle, sub_text);
1128                        printf("send sub_duration_ms=%d sub_duration_sec=%d sub_text: %s\n",sub_duration_ms, sub_duration_sec , sub_text);
1129                       
1130//                  count = sub_duration_ms / 100;
1131                        count = sub_duration_ms;
1132                        drawscreen(subtitle, 0, 0);
1133
1134                        while(count > 0 && subtitlethread->aktion != STOP)
1135                        {
1136                                usleep(100000);
1137                                count = count - 1;
1138                        }
1139                        changetext(subtitle, " ");
1140                        drawscreen(subtitle, 0, 0);
1141                        sub_duration_ms = 0;
1142                }
1143                else
1144                        usleep(100000);
1145
1146                }
1147                restorescreen(bg, subtitle);
1148                blitfb(0);
1149                free(sub_text); sub_text = NULL;
1150                subtitlethread = NULL;
1151        }
1152#endif
1153
1154#ifdef EPLAYER4
1155void playersubtitleAvail(GstElement *subsink, GstBuffer *buffer, gpointer user_data)
1156{
1157        //printf("++++++ subtitelflag: %i\n", subtitleflag);
1158        if(subtitleflag == 0 || subtitleflag == 2) return;
1159
1160#if GST_VERSION_MAJOR < 1
1161        gint64 buf_pos = GST_BUFFER_TIMESTAMP(buffer);
1162        gint64 duration_ns = GST_BUFFER_DURATION(buffer);
1163#endif 
1164        time_t running_pts = 0;
1165        gint64 pos = 0;
1166        int32_t decoder_ms;
1167        GstFormat fmt = GST_FORMAT_TIME;
1168       
1169#if GST_VERSION_MAJOR < 1
1170        if (!gst_element_query_position(pipeline, &fmt, &pos))
1171#else
1172        if (!gst_element_query_position(pipeline, fmt, &pos))
1173#endif
1174        {
1175                err("gst_element_query_position failed");
1176                return;
1177        }
1178        running_pts = pos / 11111LL;
1179        decoder_ms = running_pts / 90;
1180               
1181        if(subtitlethread == NULL)
1182                subtitlethread = addtimer(&playersubtitle_thread, START, 10000, 1, NULL, NULL, NULL);
1183       
1184#if GST_VERSION_MAJOR < 1
1185        size_t len = GST_BUFFER_SIZE(buffer);
1186#else
1187//      size_t len = gst_buffer_get_size(buffer);
1188        GstMapInfo map;
1189        if(!gst_buffer_map(buffer, &map, GST_MAP_READ))
1190        {
1191                printf("eServiceMP3::pullSubtitle gst_buffer_map failed\n");
1192                return;
1193        }
1194        gint64 buf_pos = GST_BUFFER_PTS(buffer);
1195        size_t len = map.size;
1196#if GST_VERSION_MAJOR < 1
1197        printf("gst_buffer_get_size %zu map.size %zu\n", gst_buffer_get_size(buffer), len);
1198#endif
1199        gint64 duration_ns = GST_BUFFER_DURATION(buffer);
1200#endif
1201                       
1202        //printf("BUFFER_TIMESTAMP: %lld - BUFFER_DURATION: %lld in ns\n", buf_pos, duration_ns);
1203        //printf("BUFFER_SIZE: %d\n", len);
1204        //printf("BUFFER_DATA: %s\n", GST_BUFFER_DATA(buffer));
1205       
1206        while(duration_ms != 0 && subtitlethread != NULL)
1207        {
1208                usleep(100000);
1209        }
1210        if(subtext != NULL)
1211                free(subtext);
1212        subtext = malloc(len+10);
1213        if(subtext == NULL)
1214        {
1215                err("no mem");
1216                return;
1217        }
1218#if GST_VERSION_MAJOR > 1
1219        guint8 *data;
1220//      gsize size;
1221        GstMapInfo map;
1222        gst_buffer_map(buffer, &map, GST_MAP_READ);
1223        data = map.data;
1224        sprintf(subtext, "%s", data);
1225//      sprintf(subtext, "%s", GST_BUFFER_DATA(buffer));
1226#endif
1227        playersubtitleclean(subtext, len+10);
1228       
1229        double convert_fps = 1.0;
1230        buf_pos_ms  = (buf_pos / 1000000ULL) * convert_fps;
1231        duration_ms = duration_ns / 1000000ULL;
1232
1233        //printf("++++++ buff_pos  : %u\n", buf_pos_ms);
1234        //printf("++++++ decoder_ms: %i\n", decoder_ms);
1235}
1236#endif
1237
1238#ifdef EPLAYER4
1239// set http extra-header and user-agent
1240void playbinNotifySource(GObject *object, GParamSpec *unused, char* file)
1241{
1242        printf("[player.h] playbinNotifySource: %s\n", file);
1243        GstElement *source = NULL;
1244        g_object_get(object, "source", &source, NULL);
1245        if (source)
1246        {
1247                if (g_object_class_find_property(G_OBJECT_GET_CLASS(source), "cookiejar-file-name") != 0)
1248                {
1249                        printf("[player.h] set cookiejar-file-name: /mnt/network/cookies\n");
1250                        g_object_set(G_OBJECT(source), "cookiejar-file-name", "/mnt/network/cookies", NULL);
1251                }
1252
1253                if(ostrstr(file, "|") != NULL)
1254                {
1255                        if (g_object_class_find_property(G_OBJECT_GET_CLASS(source), "extra-headers") != 0)
1256                        {
1257        #if GST_VERSION_MAJOR < 1
1258                                GstStructure *extras = gst_structure_empty_new("extras");
1259        #else
1260                                GstStructure *extras = gst_structure_new_empty("extras");
1261        #endif
1262                                char* tmpstr1 = NULL, *tmpstr2 = NULL, *tmpstr3 = NULL, *tmpstr4 = NULL;
1263                                tmpstr1 = ostrcat(file, NULL, 0, 0);
1264                                int count1 = 0, i = 0;
1265                                struct splitstr* ret1 = NULL;
1266                                ret1 = strsplit(tmpstr1, "|", &count1);
1267       
1268                                for(i = 0; i < count1; i++)
1269                                {
1270                                        if(i == 0)
1271                                        {
1272                                                printf("[player.h] playbinNotifySource: skip url string: %s\n", ret1[i].part);
1273                                                continue;
1274                                        }
1275                                        tmpstr2 = ostrcat(ret1[i].part, NULL, 0, 0);
1276       
1277                                        int count2 = 0, i2 = 0;
1278                                        struct splitstr* ret2 = NULL;
1279                                        ret2 = strsplit(tmpstr2, "&", &count2);
1280
1281                                        if(ret2 != NULL)
1282                                        {
1283                                                for(i2 = 0; i2 < count2; i2++)
1284                                                {
1285                                                        int count3 = 0, i3 = 0;
1286                                                        struct splitstr* ret3 = NULL;
1287                                                        tmpstr3 = ostrcat(ret2[i2].part, NULL, 0, 0);
1288                                                        ret3 = strsplit(tmpstr3, "=", &count3);
1289                                       
1290                                                        if(ret3 != NULL)
1291                                                        {
1292                                                                int max = count3 - 1;
1293                                                                for(i3 = 0; i3 < max; i3++)
1294                                                                {
1295                                                                        if(ostrstr(ret3[i3].part, "User-Agent") != NULL)
1296                                                                        {
1297                        //                                                      printf("[player.h] skip set user-agent: %s\n", ret2[1].part);
1298                                                                                printf("[player.h] set user-agent: %s\n", ret3[i3 + 1].part);
1299                                                                                g_object_set(G_OBJECT(source), "user-agent", ret3[i3 + 1].part, NULL);
1300                                                                        }
1301                                                                        else
1302                                                                        {
1303                                                                                if (g_object_class_find_property(G_OBJECT_GET_CLASS(source), "extra-headers") != 0)
1304                                                                                {                                       
1305                                                                                        GValue header;
1306                                                                                        // eDebug("setting extra-header '%s:%s'", name.c_str(), value.c_str());
1307                                                                                        printf("[player.h] set extra-header %s: %s\n", ret3[i3].part, ret3[i3 + 1].part);
1308                                                                                       
1309                                                                                        tmpstr4 = ostrcat(ret3[i3 + 1].part, NULL, 0, 0);
1310                                                                                        htmldecode(tmpstr4, tmpstr4);
1311                                                                                        printf("[player.h] set extra-header decode %s: %s\n", ret3[i3].part, tmpstr4);
1312                       
1313                                                                                        memset(&header, 0, sizeof(GValue));
1314                                                                                        g_value_init(&header, G_TYPE_STRING);
1315                                                                                        //value
1316                                                                                        g_value_set_string(&header, tmpstr4);
1317                                                                                        //name
1318                                                                                        gst_structure_set_value(extras, ret3[i3].part, &header);
1319                                                                                        free(tmpstr4), tmpstr4 = NULL;
1320                                                                                }
1321                                                                        }
1322                                                                }
1323                                                        }
1324                                                        free(ret3), ret3 = NULL;
1325                                                        free(tmpstr3), tmpstr3 = NULL;
1326                                                }
1327                                        }
1328                                        free(ret2), ret2 = NULL;
1329                                        free(tmpstr2), tmpstr2 = NULL;
1330                                }
1331
1332                                free(ret1), ret1 = NULL;
1333                                free(tmpstr1), tmpstr1 = NULL;
1334
1335                                if (gst_structure_n_fields(extras) > 0)
1336                                {
1337                                        g_object_set(G_OBJECT(source), "extra-headers", extras, NULL);
1338                                }
1339                                gst_structure_free(extras);
1340                        }
1341                }
1342
1343                if (g_object_class_find_property(G_OBJECT_GET_CLASS(source), "ssl-strict") != 0)
1344                {
1345                        printf("[player.h] set ssl-strict\n");
1346                        g_object_set(G_OBJECT(source), "ssl-strict", FALSE, NULL);
1347                }
1348        }
1349        gst_object_unref(source);
1350}
1351#endif
1352
1353//extern player
1354int playerstart(char* file)
1355{
1356        char * tmpfile = NULL;
1357        status.prefillbuffer = 0;
1358       
1359        addconfig("lastplayertype", "0");
1360       
1361#ifdef EPLAYER4
1362        status.prefillbuffercount = 0;
1363        status.bufferpercent = 0;
1364#endif 
1365        if(file != NULL)
1366        {
1367#ifdef EPLAYER3
1368                //use eplayer
1369
1370                if(player != NULL)
1371                {
1372                        debug(150, "eplayer allready running");
1373                        playerstop();
1374                }
1375
1376                player = calloc(1, sizeof(Context_t));
1377
1378                if(player == NULL)
1379                {
1380                        err("no mem");
1381                        return 1;
1382                }
1383
1384                if(ostrstr(file, "://") == NULL)
1385                        tmpfile = ostrcat("file://", file, 0, 0);
1386                else
1387                        tmpfile = ostrcat(file, NULL, 0, 0);
1388
1389                if(tmpfile == NULL)
1390                {
1391                        err("no mem");
1392                        free(player); player = NULL;
1393                        return 1;
1394                }
1395// move to mc
1396//              set_player_sound(0);
1397
1398                if(ostrstr(tmpfile, "file://") == NULL)
1399                        status.playercan = 0x4650;
1400                else
1401                        status.playercan = 0xFFFF;
1402
1403                player->playback = &PlaybackHandler;
1404                player->output = &OutputHandler;
1405                player->container = &ContainerHandler;
1406                player->manager = &ManagerHandler;
1407
1408//#ifndef EXTEPLAYER3           
1409                //add container befor open, so we can set buffer size
1410                char* extffm = getfilenameext(tmpfile);
1411                if(extffm != NULL)
1412                {
1413                        player->container->Command(player, CONTAINER_ADD, extffm);
1414                        free(extffm); extffm = NULL;
1415                }
1416
1417                //select container_ffmpeg, if we does not found a container with extensions
1418                if(player->container->selectedContainer == NULL)
1419                        player->container->Command(player, CONTAINER_ADD, "mp3");
1420//#endif
1421
1422                if(player && player->container && player->container->selectedContainer)
1423                {
1424#ifndef EXTEPLAYER3
1425                        int32_t size = getconfigint("playerbuffersize", NULL);
1426                        int32_t seektime = getconfigint("playerbufferseektime", NULL);
1427#else
1428                        int32_t* size = (int32_t*)getconfigint("playerbuffersize", NULL);
1429                        int32_t* seektime = (int32_t*)getconfigint("playerbufferseektime", NULL);
1430
1431                        if(strstr(tmpfile, "http://") == tmpfile || strstr(tmpfile, "https://") == tmpfile)
1432                                progressive_playback_set(1);
1433
1434//                      if(ostrcmp(getconfig("av_ac3mode", NULL), "downmix") == 0)
1435#ifndef MIPSEL
1436                        int tmpdownmix = 0;
1437                        char* downmix = readfiletomem(getconfig("ac3dev", NULL), 1);
1438//                      printf("ac3dev: %s\n",getconfig("ac3dev", NULL));
1439                        debug(150, "ac3dev=%s", getconfig("ac3dev", NULL));
1440
1441//                      printf("downmix: %s\n",downmix);
1442                        debug(150, "downmix=%s", downmix);
1443
1444//                      if(ostrcmp(downmix, "downmix") == 0)
1445                        if(ostrstr(downmix, "downmix") != NULL)
1446                                tmpdownmix = 1;
1447                        else
1448                                tmpdownmix = 0;
1449
1450                        debug(150, "tmpdownmix=%d", tmpdownmix);
1451
1452                        free(downmix), downmix = NULL;
1453                        if(tmpdownmix != status.downmix)
1454                        {
1455                                debug(150, "change downmix=%d to downmix=%d", status.downmix, tmpdownmix);
1456                        }
1457
1458//                      printf("status.downmix: %d\n",status.downmix);
1459                        debug(150, "tmpdownmix=%d", tmpdownmix);
1460                        debug(150, "status.downmix=%d", status.downmix);
1461
1462                        if(tmpdownmix == 1)
1463                        {
1464                                debug(150, "enable dts downmix");
1465                                dts_software_decoder_set(1);
1466                                stereo_software_decoder_set(1);
1467                        }
1468#endif
1469//                      container_set_ffmpeg_buf_size(size);
1470#endif
1471
1472                        player->container->selectedContainer->Command(player, CONTAINER_SET_BUFFER_SIZE, (void*)&size);
1473                        player->container->selectedContainer->Command(player, CONTAINER_SET_BUFFER_SEEK_TIME, (void*)&seektime);
1474                }
1475               
1476                debug(150, "eplayername = %s", player->output->Name);
1477#ifdef EXTEPLAYER3
1478            // make sure to kill myself when parent dies
1479            prctl(PR_SET_PDEATHSIG, SIGKILL);
1480
1481            SetBuffering();
1482#endif
1483                //Registrating output devices
1484                player->output->Command(player, OUTPUT_ADD, "audio");
1485                player->output->Command(player, OUTPUT_ADD, "video");
1486                player->output->Command(player, OUTPUT_ADD, "subtitle");
1487#ifndef EXTEPLAYER3
1488                //for subtitle
1489//              SubtitleOutputDef_t subout;
1490
1491//              subout.screen_width = skinfb->width;
1492//              subout.screen_height = skinfb->height;
1493//              subout.framebufferFD = skinfb->fd;
1494//              subout.destination = (uint32_t *)skinfb->fb;
1495//              subout.destStride = skinfb->pitch;
1496//              subout.shareFramebuffer = 1;
1497//              subout.framebufferBlit = blitfb1;
1498
1499//              player->output->subtitle->Command(player, (OutputCmd_t)OUTPUT_SET_SUBTITLE_OUTPUT, (void*)&subout);
1500
1501                if(player->playback->Command(player, PLAYBACK_OPEN, tmpfile) < 0)
1502                {
1503                        free(player); player = NULL;
1504                        free(tmpfile);
1505                        return 1;
1506                }
1507#else
1508            player->manager->video->Command(player, MANAGER_REGISTER_UPDATED_TRACK_INFO, UpdateVideoTrack);
1509            if (strncmp(file, "rtmp", 4) && strncmp(file, "ffrtmp", 4))
1510            {
1511                player->playback->noprobe = 1;
1512            }
1513       
1514                char* audioFile = NULL;
1515            PlayFiles_t playbackFiles = {tmpfile, NULL};
1516            if('\0' != audioFile[0])
1517            {
1518                playbackFiles.szSecondFile = audioFile;
1519            }
1520
1521                //for subtitle
1522//              SubtitleOutputDef_t subout;
1523
1524//              subout.screen_width = skinfb->width;
1525//              subout.screen_height = skinfb->height;
1526//              subout.framebufferFD = skinfb->fd;
1527//              subout.destination = (uint32_t *)skinfb->fb;
1528//              subout.destStride = skinfb->pitch;
1529//              subout.shareFramebuffer = 1;
1530//              subout.framebufferBlit = blitfb1;
1531
1532//              player->output->subtitle->Command(player, (OutputCmd_t)OUTPUT_SET_SUBTITLE_OUTPUT, (void*)&subout);
1533
1534                if(player->playback->Command(player, PLAYBACK_OPEN, &playbackFiles) < 0)
1535                {
1536                        free(player); player = NULL;
1537                        free(tmpfile);
1538                        return 1;
1539                }
1540#endif         
1541
1542
1543                player->output->Command(player, OUTPUT_OPEN, NULL);
1544                player->playback->Command(player, PLAYBACK_PLAY, NULL);
1545
1546                free(tmpfile);
1547
1548                return 0;
1549#endif
1550
1551#ifdef EPLAYER4
1552                int flags = 0x47; //(GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_NATIVE_VIDEO | GST_PLAY_FLAG_TEXT);
1553               
1554                if(pipeline != NULL)
1555                {
1556                        debug(150, "eplayer allready running");
1557                        playerstop();
1558                }
1559               
1560                if(ostrstr(file, "://") == NULL)
1561                        tmpfile = ostrcat("file://", file, 0, 0);
1562                else
1563                        tmpfile = ostrcat(file, NULL, 0, 0);
1564
1565                printf("[player.h] file: %s\n", file);
1566
1567                if(tmpfile == NULL)
1568                {
1569                        err("no mem");
1570                        free(pipeline); pipeline = NULL;
1571                        return 1;
1572                }
1573
1574                if(ostrstr(tmpfile, "file://") == NULL)
1575                        //status.playercan = 0x7E7F;
1576                        //status.playercan = 0x7EFF;
1577                        status.playercan = 0xFEFF;
1578                else
1579                        //status.playercan = 0x7E7F;
1580                        //status.playercan = 0x7EFF;
1581                        status.playercan = 0xFEFF;
1582               
1583                m_framerate = -1;
1584#if GST_VERSION_MAJOR < 1
1585                pipeline = gst_element_factory_make("playbin2", "playbin");
1586#else
1587                pipeline = gst_element_factory_make("playbin", "playbin");
1588#endif
1589
1590// enable buffersize start
1591                int size = getconfigint("playerbuffersize", NULL);
1592                printf("size: %d\n",size);
1593               
1594                if(size > 0 && ostrstr(tmpfile, "file://") == NULL)
1595                        status.prefillbuffer = 1;
1596
1597/*
1598        if (g_object_class_find_property(G_OBJECT_GET_CLASS(pipeline), "user-agent") != 0)
1599                        printf("11111111111111\n");
1600        if (g_object_class_find_property(G_OBJECT_GET_CLASS(pipeline), "cookie") != 0)
1601                        printf("22222222222222\n");
1602        if (g_object_class_find_property(G_OBJECT_GET_CLASS(pipeline), "extra-headers") != 0)
1603                        printf("33333333333333\n");
1604
1605                if(ostrstr(file, "|User-Agent=") != NULL || ostrstr(file, "|Cookie=") != NULL || ostrstr(file, "|Referer=") != NULL)
1606                {
1607                        char* tmpstr = NULL, *tmpstr1 = NULL;
1608                        tmpstr = ostrcat(file, NULL, 0, 0);
1609//                      tmpstr = string_replace("|User-Agent=", "|", tmpstr, 1);
1610                        int count1 = 0, i = 0;
1611                        struct splitstr* ret1 = NULL;
1612                        ret1 = strsplit(tmpstr, "|", &count1);
1613
1614                        int max = count1;
1615                        for(i = 0; i < max; i++)
1616                        {
1617                                if(ostrstr(ret1[i].part, "User-Agent=") != NULL)
1618                                {
1619                                        tmpstr1 = ostrcat(ret1[i].part, NULL, 0, 0);
1620                                        tmpstr1 = string_replace("User-Agent=", "", tmpstr1, 1);
1621                                        printf("[player.h] set user-agent: %s\n", tmpstr1);
1622                                        g_object_set(G_OBJECT(pipeline), "user-agent", tmpstr1, NULL);
1623                                        free(tmpstr1), tmpstr1 = NULL;
1624                                }
1625                                if(ostrstr(ret1[i].part, "Cookie=") != NULL)
1626                                {
1627                                        tmpstr1 = ostrcat(ret1[i].part, NULL, 0, 0);
1628                                        tmpstr1 = string_replace("Cookie=", "", tmpstr1, 1);
1629                                        printf("[player.h] set cookie: %s\n", tmpstr1);
1630
1631                                        gchar **cookie;
1632//                                      cookie = g_strsplit ("foo=1234,bar=9871615348162523726337x99FB", ",", -1);
1633                                        cookie = g_strsplit (tmpstr1, ",", -1);
1634                                        g_object_set (G_OBJECT(pipeline), "http-headers", cookie, NULL);
1635                                        g_strfreev (cookie);
1636                                        free(tmpstr1), tmpstr1 = NULL;
1637                                }
1638                                if(ostrstr(ret1[i].part, "Referer=") != NULL)
1639                                {
1640                                        tmpstr1 = ostrcat(ret1[i].part, NULL, 0, 0);
1641                                        tmpstr1 = string_replace("Referer=", "", tmpstr1, 1);
1642                                        printf("[player.h] set referer dummy: %s\n", tmpstr1);
1643                                        free(tmpstr1), tmpstr1 = NULL;
1644                                }
1645                        }
1646                        free(ret1), ret1 = NULL;
1647                        free(tmpstr), tmpstr = NULL;
1648//                      g_object_set(G_OBJECT(pipeline), "user-agent", "Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:30.0) Gecko/20100101 Firefox/30.0", NULL);
1649                        stringreplacechar(tmpfile, '|', '\0');
1650                        printf("tmpfile changed: %s\n", tmpfile);
1651                }
1652*/
1653
1654// strip url
1655                stringreplacechar(tmpfile, '|', '\0');
1656
1657                g_object_set(G_OBJECT(pipeline), "buffer-duration", size * GST_SECOND, NULL);
1658                g_object_set(G_OBJECT(pipeline), "buffer-size", size, NULL);
1659// enable buffersizeend
1660
1661                g_object_set(G_OBJECT(pipeline), "uri", tmpfile, NULL);
1662                g_object_set(G_OBJECT(pipeline), "flags", flags, NULL);
1663                free(tmpfile); tmpfile = NULL;
1664
1665///////////////////
1666// srt subs start
1667                const char *filename = file;
1668                const char *ext = strrchr(filename, '.');
1669                if (!ext)
1670                        ext = filename + strlen(filename);
1671
1672                GstElement *subsink = gst_element_factory_make("subsink", "subtitle_sink");
1673                if (!subsink)
1674                        printf("sorry, can't play: missing gst-plugin-subsink\n");
1675                else
1676                {
1677//                      m_subs_to_pull_handler_id = g_signal_connect (subsink, "new-buffer", G_CALLBACK (gstCBsubtitleAvail), this);
1678                        g_signal_connect (subsink, "new-buffer", G_CALLBACK (playersubtitleAvail), NULL);
1679
1680                        g_object_set (G_OBJECT (subsink), "caps", gst_caps_from_string("text/plain; text/x-plain; text/x-raw; text/x-pango-markup; video/x-dvd-subpicture; subpicture/x-pgs"), NULL);
1681
1682#if GST_VERSION_MAJOR < 1
1683                        g_object_set (G_OBJECT (subsink), "caps", gst_caps_from_string("text/plain; text/x-plain; text/x-raw; text/x-pango-markup; video/x-dvd-subpicture; subpicture/x-pgs"), NULL);
1684#else
1685                        g_object_set (G_OBJECT (subsink), "caps", gst_caps_from_string("text/plain; text/x-plain; text/x-raw; text/x-pango-markup; subpicture/x-dvd; subpicture/x-pgs"), NULL);
1686#endif
1687
1688                        g_object_set (G_OBJECT (pipeline), "text-sink", subsink, NULL);
1689                        subtitleflag = 1;
1690                        //g_object_set (G_OBJECT (pipeline), "current-text", -1, NULL);
1691                }
1692
1693//////////////////////////
1694// enable soup user-agent / extra-headers
1695                g_signal_connect(G_OBJECT(pipeline), "notify::source", G_CALLBACK(playbinNotifySource), file);
1696//////////////////////////
1697
1698                printf("[player.h] file changed: %s\n", file);
1699
1700//gpointer this;
1701//memset (&this, 0, sizeof (this));
1702
1703                GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
1704#if GST_VERSION_MAJOR < 1
1705//              gst_bus_set_sync_handler(bus, gstBusSyncHandler, this);
1706                gst_bus_set_sync_handler(bus, GST_BUS_DROP, NULL);
1707#else
1708//              gst_bus_set_sync_handler(bus, gstBusSyncHandler, this, NULL);
1709                gst_bus_set_sync_handler(bus, GST_BUS_DROP, NULL, NULL);
1710#endif
1711
1712                gst_object_unref(bus);
1713                char srt_filename[ext - filename + 5];
1714                strncpy(srt_filename,filename, ext - filename);
1715                srt_filename[ext - filename] = '\0';
1716                strcat(srt_filename, ".srt");
1717
1718                if(access(srt_filename, R_OK) >= 0)
1719                {
1720                        printf("found srt1: %s\n",srt_filename);
1721                        printf("found srt2: %s\n",g_filename_to_uri(srt_filename, NULL, NULL));
1722                        g_object_set(G_OBJECT (pipeline), "suburi", g_filename_to_uri(srt_filename, NULL, NULL), NULL);
1723                }
1724// srt end     
1725
1726///////////////////
1727//              CustomData data;
1728                memset (&data, 0, sizeof (data));
1729                data.pipeline = pipeline;
1730//              GstBus *bus;
1731//              bus = gst_element_get_bus (pipeline);
1732               
1733                // Start playing //
1734
1735                GstStateChangeReturn ret;
1736                ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
1737                g_object_set (G_OBJECT (pipeline), "current-text", 0, NULL);
1738                if(ret == GST_STATE_CHANGE_FAILURE)
1739                {
1740                        g_printerr ("Unable to set the pipeline to the playing state.\n");
1741                        gst_object_unref (pipeline);
1742                        return -1;
1743                }
1744                else if(ret == GST_STATE_CHANGE_NO_PREROLL)
1745                {
1746                        data.is_live = TRUE;
1747                }
1748
1749                data.loop = g_main_loop_new (NULL, FALSE);
1750                data.pipeline = pipeline;
1751                gst_bus_add_signal_watch (bus);
1752//              g_signal_connect (bus, "message", G_CALLBACK (cb_message), &data);
1753//              status.prefillbuffer = 1;
1754
1755//analyze_streams(data);
1756
1757                int count = 0;
1758                m_gst_startpts = 0;
1759                while(m_gst_startpts == 0 && count < 5)
1760                {
1761                        count++;
1762                        sleep(1);
1763                        m_gst_startpts = playergetpts();
1764                }
1765
1766                return 0;
1767#endif
1768        }
1769       
1770        return 1;
1771}
1772
1773#ifdef EPLAYER4
1774int setBufferSize(int size)
1775{
1776        int m_buffer_size = size;
1777        g_object_set (G_OBJECT (pipeline), "buffer-size", m_buffer_size, NULL);
1778        return 0;
1779}
1780#endif
1781
1782void playerinit(int argc, char* argv[])
1783{
1784#ifdef EPLAYER4
1785//      GstBus *bus;
1786//      GstStateChangeReturn ret;
1787//      gint flags;
1788        gst_init(&argc, &argv);
1789#endif
1790}
1791
1792#ifdef EPLAYER4
1793int gstbuscall(GstBus *bus, GstMessage *msg, CustomData *data)
1794{
1795        int ret = 1;
1796        if(!pipeline) return 0;
1797        if(!msg) return ret;
1798
1799        gchar *sourceName = NULL;
1800        GstObject *source = GST_MESSAGE_SRC(msg);
1801
1802        if(!GST_IS_OBJECT(source)) return ret;
1803        sourceName = gst_object_get_name(source);
1804
1805        debug(150, "gst type: %s", GST_MESSAGE_TYPE_NAME(msg));
1806
1807        switch(GST_MESSAGE_TYPE(msg))
1808        {
1809                case GST_MESSAGE_EOS:
1810                        debug(150, "gst player eof");
1811                        ret = 0;
1812                        break;
1813                case GST_MESSAGE_STATE_CHANGED:
1814                        debug(150, "gst message state changed");
1815                        if(GST_MESSAGE_SRC(msg) != GST_OBJECT(pipeline))
1816                                break;
1817
1818                        GstState old_state, new_state, pending_state;
1819                        gst_message_parse_state_changed(msg, &old_state, &new_state, &pending_state);
1820                        if(GST_MESSAGE_SRC(msg) == GST_OBJECT(pipeline))
1821                        {
1822                                if(new_state == GST_STATE_PLAYING)
1823                                {
1824                                        /* Once we are in the playing state, analyze the streams */
1825                                        analyze_streams(data);
1826                                }
1827                        }
1828
1829                        if(old_state == new_state) break;
1830       
1831                        debug(150, "gst state change %s -> %s", gst_element_state_get_name(old_state), gst_element_state_get_name(new_state));
1832       
1833                        GstStateChange transition = (GstStateChange)GST_STATE_TRANSITION(old_state, new_state);
1834       
1835                        switch(transition)
1836                        {
1837                                case GST_STATE_CHANGE_NULL_TO_READY:
1838                                        break;
1839                                case GST_STATE_CHANGE_READY_TO_PAUSED:
1840/*
1841                                        GstElement *appsink = gst_bin_get_by_name(GST_BIN(pipeline), "subtitle_sink");
1842                                        if(appsink)
1843                                        {
1844                                                g_object_set(G_OBJECT(appsink), "max-buffers", 2, NULL);
1845                                                g_object_set(G_OBJECT(appsink), "sync", FALSE, NULL);
1846                                                g_object_set(G_OBJECT(appsink), "emit-signals", TRUE, NULL);
1847                                                gst_object_unref(appsink);
1848                                        }
1849*/
1850                                        break;
1851                                case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1852                                        //if(m_sourceinfo.is_streaming && m_streamingsrc_timeout )
1853                                                //m_streamingsrc_timeout->stop();
1854                                        break;
1855                                case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1856                                        break;
1857                                case GST_STATE_CHANGE_PAUSED_TO_READY:
1858                                        break;
1859                                case GST_STATE_CHANGE_READY_TO_NULL:
1860                                        ret = 0;
1861                                        break;
1862                        }
1863                        break;
1864                case GST_MESSAGE_ERROR:
1865                        debug(150, "gst player error");
1866
1867                        gchar *gdebug1;
1868                        GError *err;
1869
1870                        gst_message_parse_error(msg, &err, &gdebug1);
1871                        g_free(gdebug1);
1872
1873                        debug(150, "gst error: %s (%i) from %s", err->message, err->code, sourceName);
1874                        if(err->domain == GST_STREAM_ERROR)
1875                        {
1876                                if(err->code == GST_STREAM_ERROR_CODEC_NOT_FOUND )
1877                                {
1878                                        //if(g_strrstr(sourceName, "videosink"))
1879                                        //      m_event((iPlayableService*)this, evUser+11);
1880                                        //else if ( g_strrstr(sourceName, "audiosink") )
1881                                        //      m_event((iPlayableService*)this, evUser+10);
1882                                }
1883                        }
1884                        g_error_free(err);
1885                        break;
1886                case GST_MESSAGE_INFO:
1887                        debug(150, "gst player info");
1888
1889/*
1890                        gchar *gdebug2;
1891                        GError *inf;
1892       
1893                        gst_message_parse_info(msg, &inf, &gdebug2);
1894                        g_free(gdebug2);
1895                        if(inf->domain == GST_STREAM_ERROR && inf->code == GST_STREAM_ERROR_DECODE )
1896                        {
1897                                //if(g_strrstr(sourceName, "videosink"))
1898                                //      m_event((iPlayableService*)this, evUser+14);
1899                        }
1900                        g_error_free(inf);
1901*/
1902                        break;
1903                case GST_MESSAGE_TAG:
1904                        debug(150, "gst player tag");
1905                        break;
1906                //case GST_MESSAGE_ASYNC_DONE:
1907                //      debug(150, "gst player async done");
1908                //      break;
1909                case GST_MESSAGE_ELEMENT:
1910                        debug(150, "GST_MESSAGE_ELEMENT");
1911                        const GstStructure *msgstruct = gst_message_get_structure(msg);
1912                        if (msgstruct)
1913                        {
1914                                const gchar *eventname = gst_structure_get_name(msgstruct);
1915                                if (!strcmp(eventname, "eventFrameRateChanged") || !strcmp(eventname, "eventFrameRateAvail"))
1916                                {
1917                                        gst_structure_get_int (msgstruct, "frame_rate", &m_framerate);
1918                                }
1919                        }
1920                        debug(150, "gst player element");
1921                        break;
1922                case GST_MESSAGE_BUFFERING:
1923                        debug(150, "gst player buffering");
1924
1925/*
1926                        GstBufferingMode mode;
1927                        gst_message_parse_buffering(msg, &(m_bufferInfo.bufferPercent));
1928                        gst_message_parse_buffering_stats(msg, &mode, &(m_bufferInfo.avgInRate), &(m_bufferInfo.avgOutRate), &(m_bufferInfo.bufferingLeft));
1929                        //m_event((iPlayableService*)this, evBuffering);
1930*/
1931
1932// playback stream jerky on start
1933//                      if (data->is_live) break;
1934//                      gst_message_parse_buffering (msg, &status.bufferpercent);
1935
1936                        if(status.prefillbuffer == 1)
1937                        {
1938                                status.prefillbuffercount++;
1939                                if(status.prefillbuffercount >= 200 && status.bufferpercent < 2)
1940                                {
1941                                        printf("status.prefillbuffercount >= 200 set status.prefillbuffer=2\n");
1942                                        status.prefillbuffer = 2;
1943                                }
1944                        }
1945                        debug(150, "status.prefillbuffercount=%d status.cleaninfobar=%d status.prefillbuffer=%d status.bufferpercent=%d",status.prefillbuffercount , status.cleaninfobar, status.prefillbuffer, status.bufferpercent);
1946                       
1947                        if(status.prefillbuffer == 1)
1948                        {
1949//                              gint percent = 0;
1950                                if (data->is_live)
1951                                {
1952                                        printf("data->is_live break: status.cleaninfobar=%d status.prefillbuffer=%d status.bufferpercent=%d\n", status.cleaninfobar, status.prefillbuffer, status.bufferpercent);
1953                                        break;
1954                                }
1955
1956                                gst_message_parse_buffering (msg, &status.bufferpercent);
1957                                g_print ("Buffering (%3d%%)\r", status.bufferpercent);
1958
1959                                if (status.bufferpercent < 100)
1960                                {
1961                                        gst_element_set_state (data->pipeline, GST_STATE_PAUSED);
1962                                        struct skin* waitmsgbar = getscreen("waitmsgbar");
1963                                        struct skin* load = getscreen("loading");
1964       
1965                                        waitmsgbar->progresssize = status.bufferpercent;
1966                                        char* tmpstr = NULL;
1967                                        tmpstr = ostrcat(_("Buffering Stream - Cancel with Exit"), " (", 0, 0);
1968                                        tmpstr = ostrcat(tmpstr, oitoa(waitmsgbar->progresssize), 1, 0);
1969                                        tmpstr = ostrcat(tmpstr, "%)", 1, 0);
1970                                        changetext(waitmsgbar, tmpstr);
1971                                        free(tmpstr); tmpstr = NULL;
1972       
1973                                        drawscreen(load, 0, 0);
1974                                        drawscreen(waitmsgbar, 0, 0);
1975                                        status.cleaninfobar = 0;
1976                                }
1977                                else
1978                                {
1979                                        drawscreen(skin, 0, 0);
1980                                        gst_element_set_state (data->pipeline, GST_STATE_PLAYING);
1981                                        status.prefillbuffer = 0;
1982                                        status.cleaninfobar = 1;
1983                                }
1984       
1985                        }
1986                        else if(status.prefillbuffer == 2)
1987                        {
1988                                drawscreen(skin, 0, 0);
1989                                gst_element_set_state (data->pipeline, GST_STATE_PLAYING);
1990                                status.prefillbuffer = 0;
1991                                status.cleaninfobar = 1;
1992                        }
1993                        else if(status.cleaninfobar == 1)
1994                        {
1995                                drawscreen(skin, 0, 0);
1996                                status.cleaninfobar = 0;
1997                        }
1998                        else
1999                        {
2000//                      printf("else\n");
2001                                gst_message_parse_buffering (msg, &status.bufferpercent);
2002                                g_print ("Buffering (%3d%%)\r", status.bufferpercent);
2003//                              drawscreen(skin, 0, 0);
2004//                              status.cleaninfobar = 0;
2005                        }
2006                        break;
2007 
2008/*
2009                        GstBufferingMode mode;
2010                        gst_message_parse_buffering(msg, &(status.bufferpercent));
2011                        gst_message_parse_buffering_stats(msg, &mode, &(status.avgInRate), &(status.avgOutRate), &(status.bufferingLeft));
2012
2013//                      printf("#########################################################\n");
2014//                      printf("Buffering %u percent done\n", status.bufferpercent);
2015//                      printf("avgInRate %d\n", status.avgInRate);
2016//                      printf("avgOutRate %d\n", status.avgOutRate);
2017//                      printf("bufferingLeft %lld\n", status.bufferingLeft);
2018                                       
2019                        if(status.prefillbuffer == 1)
2020                        {
2021                                printf("status.prefillbuffer Buffering %u percent done\n", status.bufferpercent);
2022
2023                                if (status.bufferpercent == 100)
2024                                {
2025                                        GstState state;
2026                                        gst_element_get_state(pipeline, &state, NULL, 0LL);
2027                                        if (state != GST_STATE_PLAYING)
2028                                        {
2029                                                // eDebug("start playing");
2030                                                gst_element_set_state (pipeline, GST_STATE_PLAYING);
2031                                        }
2032//                                      m_ignore_buffering_messages = 5;
2033                                        status.prefillbuffer = 0;
2034                                }
2035                                else if (status.bufferpercent == 0)
2036                                {
2037                                        // eDebug("start pause");
2038                                        gst_element_set_state (pipeline, GST_STATE_PAUSED);
2039//                                      m_ignore_buffering_messages = 0;
2040                                }
2041                        }
2042*/
2043/*
2044                                GstBufferingMode mode;
2045                                printf("GST_STATE_PAUSED\n");
2046                                gst_element_set_state (pipeline, GST_STATE_PAUSED);
2047
2048
2049                                gst_message_parse_buffering(msg, &(m_bufferInfo.bufferPercent));
2050                                // eDebug("Buffering %u percent done", m_bufferInfo.bufferPercent);
2051                                gst_message_parse_buffering_stats(msg, &mode, &(m_bufferInfo.avgInRate), &(m_bufferInfo.avgOutRate), &(m_bufferInfo.bufferingLeft));
2052                                m_event((iPlayableService*)this, evBuffering);
2053                                if (m_use_prefillbuffer && !m_is_live && --m_ignore_buffering_messages <= 0)
2054                                {
2055                                        if (m_bufferInfo.bufferPercent == 100)
2056                                        {
2057                                                GstState state;
2058                                                gst_element_get_state(pipeline, &state, NULL, 0LL);
2059                                                if (state != GST_STATE_PLAYING)
2060                                                {
2061                                                        // eDebug("start playing");
2062                                                        gst_element_set_state (pipeline, GST_STATE_PLAYING);
2063                                                }
2064                                                m_ignore_buffering_messages = 5;
2065                                        }
2066                                        else if (m_bufferInfo.bufferPercent == 0)
2067                                        {
2068                                                // eDebug("start pause");
2069                                                gst_element_set_state (pipeline, GST_STATE_PAUSED);
2070                                                m_ignore_buffering_messages = 0;
2071                                        }
2072                                        else
2073                                        {
2074                                                m_ignore_buffering_messages = 0;
2075                                        }
2076                                }
2077
2078*/
2079                        break;
2080                case GST_MESSAGE_STREAM_STATUS:
2081                        debug(150, "gst player stream status");
2082
2083/*
2084                        GstStreamStatusType type;
2085                        GstElement *owner;
2086
2087                        gst_message_parse_stream_status(msg, &type, &owner);
2088                        if(type == GST_STREAM_STATUS_TYPE_CREATE && m_sourceinfo.is_streaming)
2089                        {
2090                                if(GST_IS_PAD(source))
2091                                        owner = gst_pad_get_parent_element(GST_PAD(source));
2092                                else if(GST_IS_ELEMENT(source))
2093                                        owner = GST_ELEMENT(source);
2094                                else
2095                                        owner = NULL;
2096                                if(owner)
2097                                {
2098                                        GstElementFactory *factory = gst_element_get_factory(GST_ELEMENT(owner));
2099                                        const gchar *name = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(factory));
2100                                        if (!strcmp(name, "souphttpsrc"))
2101                                        {
2102                                                //m_streamingsrc_timeout->start(10 * 1000, true);
2103                                                g_object_set(G_OBJECT(owner), "timeout", 10, NULL);
2104                                        }
2105                                       
2106                                }
2107                                if(GST_IS_PAD(source))
2108                                        gst_object_unref(owner);
2109                        }
2110*/
2111                        break;
2112                default:
2113                        debug(150, "gst player unknown message");
2114                        break;
2115        }
2116        g_free(sourceName);
2117        return ret;
2118}
2119#endif
2120
2121int playergetbuffersize()
2122{
2123        int ret = 0;
2124
2125#ifdef EPLAYER3
2126        if(player && player->container && player->container->selectedContainer)
2127                player->container->selectedContainer->Command(player, CONTAINER_GET_BUFFER_SIZE, (void*)&ret);
2128#endif
2129
2130        return ret;
2131}
2132
2133int playergetbufferstatus()
2134{
2135        int ret = 0;
2136
2137#ifdef EPLAYER3
2138        if(player && player->container && player->container->selectedContainer)
2139                player->container->selectedContainer->Command(player, CONTAINER_GET_BUFFER_STATUS, (void*)&ret);
2140#endif
2141printf("playergetbufferstatus: %d\n", ret);
2142        return ret;
2143}
2144
2145int playerstopbuffer()
2146{
2147        int ret = 0;
2148
2149#ifdef EPLAYER3
2150        if(player && player->container && player->container->selectedContainer)
2151                player->container->selectedContainer->Command(player, CONTAINER_STOP_BUFFER, NULL);
2152#endif
2153
2154        return ret;
2155}
2156
2157int playerisplaying()
2158{
2159#ifdef SIMULATE
2160        return 1;
2161#endif
2162
2163#ifdef EPLAYER3
2164        if(player != NULL && player->playback != NULL && player->playback->isPlaying)
2165                return 1;
2166#endif
2167
2168#ifdef EPLAYER4
2169        int ret = 1;
2170
2171        if(pipeline)
2172        {
2173                GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
2174                GstMessage *message = NULL;
2175//use global variale, with static var crash
2176//              CustomData *data = NULL;
2177                while((message = gst_bus_pop(bus)))
2178                {
2179                        ret = gstbuscall(bus, message, &data);
2180                        gst_message_unref(message);
2181
2182                }               
2183// fix buffering on filenuke
2184                if(status.cleaninfobar == 0 && status.prefillbuffer == 1 && status.bufferpercent == 0)
2185                        gst_element_set_state (pipeline, GST_STATE_PAUSED);
2186                       
2187// eof workaround for some mp4 files.
2188                gint64 pts = 0, len = 0, rest = 0;
2189                gint64 nanos_pts = 0, nanos_len = 0;
2190
2191                len = playergetlength();
2192                nanos_len = len * 1000000000;
2193                if(nanos_len < 0) nanos_len = 0;
2194
2195                pts = playergetpts();
2196                nanos_pts = pts * 11111;
2197
2198                rest = nanos_len - nanos_pts;
2199//              printf("rest: %lld\n", nanos_len - nanos_pts);
2200
2201                debug(150, "status.pause=%d status.playspeed=%d status.slowspeed=%d status.prefillbuffer=%d rest=%lld", status.pause, status.playspeed, status.slowspeed, status.prefillbuffer, rest);
2202                if(rest > 4000000000LL || status.pts != pts || pts == 0 || status.pause == 1 || status.playspeed != 0 || status.slowspeed != 0 /*|| status.prefillbuffer == 1*/)
2203                {
2204//                      debug(150, "status.pts=%llu / pts=%llu\n", status.pts, pts);
2205                        status.pts = pts;
2206                }
2207                else
2208                {
2209                        debug(150, "gst player eof - workaround (rest=%lld)", rest);
2210                        ret = 0;
2211                }
2212// eof workaround done
2213        }
2214        else
2215                ret = 0;
2216
2217        return ret;
2218#endif
2219        return 0;
2220}
2221
2222void playerplay()
2223{
2224#ifdef EPLAYER3
2225        if(player && player->playback)
2226                player->playback->Command(player, PLAYBACK_PLAY, NULL);
2227#endif
2228
2229#ifdef EPLAYER4
2230        if(pipeline)
2231                gst_element_set_state(pipeline, GST_STATE_PLAYING);
2232        if(subtitleflag == 2)
2233                subtitleflag = 1;
2234#endif
2235}
2236
2237int playerstop()
2238{
2239#ifdef EPLAYER3
2240        if(player && player->playback)
2241                player->playback->Command(player, PLAYBACK_STOP, NULL);
2242        if(player && player->container && player->container->selectedContainer)
2243                player->container->selectedContainer->Command(player, CONTAINER_STOP, NULL);
2244        if(player && player->output)
2245        {
2246                player->output->Command(player, OUTPUT_CLOSE, NULL);
2247                player->output->Command(player, OUTPUT_DEL, (void*)"audio");
2248                player->output->Command(player, OUTPUT_DEL, (void*)"video");
2249                player->output->Command(player, OUTPUT_DEL, (void*)"subtitle");
2250        }
2251        if(player && player->playback)
2252                player->playback->Command(player, PLAYBACK_CLOSE, NULL);
2253
2254        free(player);
2255        player = NULL;
2256
2257// move to mc
2258//      set_player_sound(1);
2259#endif
2260
2261#ifdef EPLAYER4
2262        subtitleflag = 0;
2263        if(subtitlethread != 0)
2264                subtitlethread->aktion = STOP;
2265        if(video_sink)
2266        {
2267                gst_object_unref (video_sink);
2268                video_sink = NULL;
2269        }
2270        if(pipeline)
2271        {
2272                gst_element_set_state(pipeline, GST_STATE_NULL);
2273                gst_object_unref(GST_OBJECT(pipeline));
2274                pipeline = NULL;
2275        }
2276#endif
2277
2278        writesysint("/proc/sys/vm/drop_caches", 3, 0);
2279        return 0;
2280}
2281
2282void playerafterend()
2283{
2284#ifdef EPLAYER3
2285        if(player != NULL && player->playback != NULL)
2286                playerstop();
2287#endif
2288
2289#ifdef EPLAYER4
2290        if(pipeline)
2291                playerstop();
2292#endif
2293}
2294
2295void playerpause()
2296{
2297#ifdef EPLAYER3
2298        if(status.playspeed != 0 || status.slowspeed != 0)
2299                playerff(0);
2300        if(player && player->playback)
2301                player->playback->Command(player, PLAYBACK_PAUSE, NULL);
2302#endif
2303
2304#ifdef EPLAYER4
2305        if(pipeline)
2306                gst_element_set_state(pipeline, GST_STATE_PAUSED);
2307#endif
2308}
2309
2310void playercontinue()
2311{
2312#ifdef EPLAYER3
2313        if(player && player->playback)
2314                player->playback->Command(player, PLAYBACK_CONTINUE, NULL);
2315#endif
2316
2317#ifdef EPLAYER4
2318        if(pipeline)
2319        {
2320                if(status.playspeed != 0 || status.slowspeed != 0)
2321                {
2322                        //subtitle sync bug... start
2323                        gint64 time_nanoseconds = 0;
2324                        GstFormat fmt = GST_FORMAT_TIME;
2325#if GST_VERSION_MAJOR < 1
2326                        if (!gst_element_query_position(pipeline, &fmt, &time_nanoseconds))
2327#else
2328                        if (!gst_element_query_position(pipeline, fmt, &time_nanoseconds))
2329#endif
2330                        {
2331                                err("gst_element_query_position failed");
2332                                return;
2333                        }
2334                        time_nanoseconds = time_nanoseconds - 90000;
2335                        if (!gst_element_seek (pipeline, 1, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT),GST_SEEK_TYPE_SET, time_nanoseconds,GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
2336                                printf("seekTo failed");
2337                        //subtitle sync bug... end
2338
2339                        //playersend_ff_fr_event(1);
2340                }               
2341                gst_element_set_state(pipeline, GST_STATE_PLAYING);
2342                if(subtitleflag == 2)
2343                        subtitleflag = 1;
2344        }
2345#endif
2346}
2347
2348void playerff(int speed)
2349{
2350#ifdef EPLAYER3
2351
2352        int speedmap = 0;
2353        if(speed == 0)
2354        {
2355                if(player && player->playback)
2356                {
2357                        player->playback->Command(player, PLAYBACK_FASTFORWARD, &speedmap);
2358                        return;
2359                }
2360        }
2361       
2362
2363        if (speed < 1) speed = 1;
2364        if (speed > 7) speed = 7;
2365
2366        switch(speed)
2367        {
2368                case 1: speedmap = 1; break;
2369                case 2: speedmap = 3; break;
2370                case 3: speedmap = 7; break;
2371                case 4: speedmap = 15; break;
2372                case 5: speedmap = 31; break;
2373                case 6: speedmap = 63; break;
2374                case 7: speedmap = 127; break;
2375        }
2376
2377       
2378#ifdef MIPSEL
2379        if(player && player->playback)
2380                player->playback->Command(player, PLAYBACK_CONTINUE, NULL);
2381#endif
2382#endif
2383
2384#ifdef EPLAYER4
2385        gdouble rate = 0;
2386        subtitleflag = 2;
2387        if (speed < 1) speed = 1;
2388        if (speed > 7) speed = 7;
2389
2390        switch(speed)
2391        {
2392                case 1: rate = 2; break;
2393                case 2: rate = 4; break;
2394                case 3: rate = 8; break;
2395                case 4: rate = 16; break;
2396                case 5: rate = 32; break;
2397                case 6: rate = 64; break;
2398                case 7: rate = 128; break;
2399        }
2400        playersend_ff_fr_event(rate);
2401#endif
2402}
2403
2404void playerslow(int speed)
2405{
2406#ifdef EPLAYER3
2407        int speedmap = 0;
2408#ifdef EXTEPLAYER3
2409        if (speed < 2) speed = 2;
2410        if (speed > 8) speed = 8;
2411
2412        switch(speed)
2413        {
2414                case 2: speedmap = 2; break;
2415                case 4: speedmap = 4; break;
2416                case 8: speedmap = 8; break;
2417        }
2418#else
2419        if (speed < 1) speed = 1;
2420        if (speed > 7) speed = 7;
2421
2422        switch(speed)
2423        {
2424                case 1: speedmap = 1; break;
2425                case 2: speedmap = 3; break;
2426                case 3: speedmap = 7; break;
2427                case 4: speedmap = 15; break;
2428                case 5: speedmap = 31; break;
2429                case 6: speedmap = 63; break;
2430                case 7: speedmap = 127; break;
2431        }
2432#endif
2433        if(player && player->playback)
2434                player->playback->Command(player, PLAYBACK_SLOWMOTION, &speedmap);
2435
2436#ifdef MIPSEL
2437        if(player && player->playback)
2438                player->playback->Command(player, PLAYBACK_CONTINUE, NULL);
2439#endif
2440#endif
2441
2442#ifdef EPLAYER4
2443        gdouble rate = 0;
2444        if (speed < 1) speed = 1;
2445        if (speed > 7) speed = 7;
2446               
2447        switch(speed)
2448        {
2449                case 1: rate = 0.8; break;
2450                case 2: rate = 0.7; break;
2451                case 3: rate = 0.6; break;
2452                case 4: rate = 0.5; break;
2453                case 5: rate = 0.3; break;
2454                case 6: rate = 0.2; break;
2455                case 7: rate = 0.1; break;
2456        }
2457        gst_element_set_state(pipeline, GST_STATE_PLAYING);
2458        playersend_ff_fr_event(rate);
2459       
2460#endif
2461
2462}
2463
2464void playerfr(int speed)
2465{
2466#ifdef EPLAYER3
2467        int speedmap = 0;
2468
2469        if (speed > -1) speed = -1;
2470        if (speed < -7) speed = -7;
2471
2472        switch(speed)
2473        {
2474                case -1: speedmap = -5; break;
2475                case -2: speedmap = -10; break;
2476                case -3: speedmap = -20; break;
2477                case -4: speedmap = -40; break;
2478                case -5: speedmap = -80; break;
2479                case -6: speedmap = -160; break;
2480                case -7: speedmap = -320; break;
2481        }
2482
2483        if(player && player->playback)
2484                player->playback->Command(player, PLAYBACK_FASTBACKWARD, &speedmap);
2485
2486#ifdef MIPSEL
2487        if(player && player->playback)
2488                player->playback->Command(player, PLAYBACK_CONTINUE, NULL);
2489#endif
2490#endif
2491
2492#ifdef EPLAYER4
2493        gdouble rate = 0;
2494       
2495        if (speed > -1) speed = -1;
2496        if (speed < -7) speed = -7;
2497
2498        switch(speed)
2499        {
2500                case -1: rate = -2; break;
2501                case -2: rate = -4; break;
2502                case -3: rate = -8; break;
2503                case -4: rate = -16; break;
2504                case -5: rate = -32; break;
2505                case -6: rate = -64; break;
2506                case -7: rate = -128; break;
2507        }
2508        playersend_ff_fr_event(rate);
2509#endif
2510}
2511
2512void playerseek(float sec)
2513{
2514#ifdef EPLAYER3
2515#ifdef EXTEPLAYER3
2516        int64_t sectmp = (int64_t)sec;
2517        if(player && player->playback) 
2518                player->playback->Command(player, PLAYBACK_SEEK, (void*)&sectmp);
2519#else
2520        if(player && player->playback)
2521                player->playback->Command(player, PLAYBACK_SEEK, (void*)&sec);
2522#endif
2523#endif
2524
2525#ifdef EPLAYER4
2526        gint64 nanos_pts = 0, nanos_len = 0;
2527        gint64 pts = 0, len = 0;
2528        //GstFormat fmt = GST_FORMAT_TIME;
2529               
2530        if(pipeline)
2531        {
2532                len = playergetlength();
2533                nanos_len = len * 1000000000;
2534                if(nanos_len < 0) nanos_len = 0;
2535
2536                pts = playergetpts();
2537                nanos_pts = pts * 11111;
2538                nanos_pts = nanos_pts + (sec * 1000000000);
2539                if(nanos_pts < 0) nanos_pts = 0;
2540
2541                if(nanos_pts >= nanos_len)
2542                {
2543                        debug(150, "gst skip seeking");
2544//                      playerstop();
2545                }
2546                else
2547                        gst_element_seek(pipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, nanos_pts, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
2548        }
2549#endif
2550}
2551
2552#ifdef EPLAYER4
2553audiotype_t gstCheckAudioPad(GstStructure* structure)
2554{
2555        if(!structure)
2556                return atUnknown;
2557
2558        if(gst_structure_has_name(structure, "audio/mpeg"))
2559        {
2560                gint mpegversion, layer = -1;
2561                if(!gst_structure_get_int (structure, "mpegversion", &mpegversion))
2562                        return atUnknown;
2563
2564                switch(mpegversion)
2565                {
2566                        case 1:
2567                                {
2568                                        gst_structure_get_int(structure, "layer", &layer);
2569                                        if(layer == 3)
2570                                                return atMP3;
2571                                        else
2572                                                return atMPEG;
2573                                        break;
2574                                }
2575                        case 2:
2576                                return atAAC;
2577                        case 4:
2578                                return atAAC;
2579                        default:
2580                                return atUnknown;
2581                }
2582        }
2583
2584        else if(gst_structure_has_name(structure, "audio/x-ac3") || gst_structure_has_name(structure, "audio/ac3"))
2585                return atAC3;
2586        else if(gst_structure_has_name(structure, "audio/x-dts") || gst_structure_has_name(structure, "audio/dts"))
2587                return atDTS;
2588#if GST_VERSION_MAJOR < 1
2589        else if(gst_structure_has_name(structure, "audio/x-raw-int"))
2590#else
2591        else if(gst_structure_has_name(structure, "audio/x-raw"))
2592#endif
2593                return atPCM;
2594
2595        return atUnknown;
2596}
2597
2598
2599subtype_t getSubtitleType(GstPad* pad, gchar *g_codec)
2600{
2601g_codec = NULL;
2602        subtype_t type = stUnknown;
2603#if GST_VERSION_MAJOR < 1
2604        GstCaps* caps = gst_pad_get_negotiated_caps(pad);
2605#else
2606        GstCaps* caps = gst_pad_get_current_caps(pad);
2607#endif
2608        if (!caps && !g_codec)
2609        {
2610                caps = gst_pad_get_allowed_caps(pad);
2611        }
2612
2613        if (caps && !gst_caps_is_empty(caps))
2614        {
2615                GstStructure* str = gst_caps_get_structure(caps, 0);
2616                if (str)
2617                {
2618                        const gchar *g_type = gst_structure_get_name(str);
2619                        // eDebug("getSubtitleType::subtitle probe caps type=%s", g_type ? g_type : "(null)");
2620                        if (g_type)
2621                        {
2622#if GST_VERSION_MAJOR < 1
2623                                if ( !strcmp(g_type, "video/x-dvd-subpicture") )
2624#else
2625                                if ( !strcmp(g_type, "subpicture/x-dvd") )
2626#endif
2627                                        type = stVOB;
2628                                else if ( !strcmp(g_type, "text/x-pango-markup") )
2629                                        type = stSRT;
2630                                else if ( !strcmp(g_type, "text/plain") || !strcmp(g_type, "text/x-plain") || !strcmp(g_type, "text/x-raw") )
2631                                        type = stPlainText;
2632                                else if ( !strcmp(g_type, "subpicture/x-pgs") )
2633                                        type = stPGS;
2634                                else
2635                                        printf("getSubtitleType::unsupported subtitle caps %s (%s)\n", g_type, g_codec ? g_codec : "(null)");
2636//                                      eDebug("getSubtitleType::unsupported subtitle caps %s (%s)", g_type, g_codec ? g_codec : "(null)");
2637                        }
2638                }
2639        }
2640        else if ( g_codec )
2641        {
2642                // eDebug("getSubtitleType::subtitle probe codec tag=%s", g_codec);
2643                if ( !strcmp(g_codec, "VOB") )
2644                        type = stVOB;
2645                else if ( !strcmp(g_codec, "SubStation Alpha") || !strcmp(g_codec, "SSA") )
2646                        type = stSSA;
2647                else if ( !strcmp(g_codec, "ASS") )
2648                        type = stASS;
2649                else if ( !strcmp(g_codec, "SRT") )
2650                        type = stSRT;
2651                else if ( !strcmp(g_codec, "UTF-8 plain text") )
2652                        type = stPlainText;
2653                else
2654                        printf("getSubtitleType::unsupported subtitle codec %s\n", g_codec);
2655        }
2656        else
2657                printf("getSubtitleType::unidentifiable subtitle stream!\n");
2658
2659        return type;
2660}
2661
2662#endif
2663
2664void playerfreetracklist(char** TrackList)
2665{
2666        int i = 0;
2667
2668        if(TrackList != NULL)
2669        {
2670                while(TrackList[i] != NULL)
2671                {
2672                        free(TrackList[i]);
2673                        free(TrackList[i + 1]);
2674                        i += 2;
2675                }
2676        }
2677}
2678
2679char** playergettracklist(int type)
2680{
2681#ifdef EXTEPLAYER3
2682#ifdef EPLAYER3
2683        TrackDescription_t *TrackList = NULL;
2684        char ** TrackList2 = NULL;
2685#else
2686        char ** TrackList = NULL;
2687#endif
2688#else
2689        char ** TrackList = NULL;
2690#endif
2691
2692#ifdef EPLAYER3
2693        if(player && player->manager)
2694        {
2695                switch(type)
2696                {
2697                        case 1:
2698                                if(player->manager->audio)
2699                                {
2700                                        player->manager->audio->Command(player, MANAGER_LIST, &TrackList);
2701                                        debug(150, "Audio Track List");
2702                                }
2703                                break;
2704                        case 2:
2705                                if(player->manager->subtitle)
2706                                {
2707                                        player->manager->subtitle->Command(player, MANAGER_LIST, &TrackList);
2708                                        debug(150, "Subtitle Track List");
2709                                }
2710                                break;
2711                        default:
2712                                if(player->manager->video)
2713                                {
2714                                        player->manager->video->Command(player, MANAGER_LIST, &TrackList);
2715                                        debug(150, "Video Track List");
2716                                }
2717                }
2718
2719#ifdef EXTEPLAYER3
2720                TrackList2 = calloc(1, sizeof(char *) * ((100 * 2) + 1));
2721
2722                char* tmpstr = NULL;
2723        if( NULL != TrackList)
2724        {
2725                        debug(150, "Track List");
2726
2727            int i = 0;
2728            for (i = 0; TrackList[i].Id >= 0; ++i)
2729            {
2730                                tmpstr = ostrcat(oitoa(TrackList[i].Id), ": ", 1, 0);
2731                                tmpstr = ostrcat(tmpstr, TrackList[i].Name, 1, 0);
2732                                TrackList2[i * 2] = ostrcat(tmpstr, NULL, 0, 0);
2733                                TrackList2[(i * 2) + 1] = strdup(TrackList[i].Encoding);
2734                free(TrackList[i].Encoding);
2735                free(TrackList[i].Name);
2736                                debug(150, "%s - %s", TrackList2[i * 2], TrackList2[i * 2 + 1]);
2737            }
2738            free(TrackList);
2739        }
2740        free(tmpstr), tmpstr = NULL;
2741#else
2742                int i = 0;
2743                if(TrackList != NULL)
2744                {
2745                        while(TrackList[i] != NULL)
2746                        {
2747                                string_newline(TrackList[i]);
2748                                i += 2;
2749                        }
2750                       
2751                        debug(150, "Track List");
2752                        i = 0;
2753                        while(TrackList[i] != NULL)
2754                        {
2755                                debug(150, "%s - %s", TrackList[i], TrackList[i + 1]);
2756                                i += 2;
2757                        }
2758                }
2759#endif
2760        }
2761#endif
2762
2763//////////////////////////////NEUER CODE //////////////////////////////
2764#ifdef EPLAYER4
2765        TrackList = calloc(1, sizeof(char *) * ((100 * 2) + 1));
2766       
2767        if(pipeline != NULL)
2768        {
2769                gint i, n_video = 0, n_audio = 0, n_text = 0;
2770               
2771                g_object_get(pipeline, "n-video", &n_video, NULL);
2772                g_object_get(pipeline, "n-audio", &n_audio, NULL);
2773                g_object_get(pipeline, "n-text", &n_text, NULL);
2774
2775                switch(type)
2776                {
2777                        case 1:
2778                                for(i = 0; i < n_audio; i++)
2779                                {
2780                                        GstTagList *tags = NULL;
2781                                        gchar *g_codec = NULL, *g_lang = NULL;
2782                                        char* tmpstr = NULL;
2783                                        GstPad* pad = 0;
2784                                       
2785                                        g_signal_emit_by_name (pipeline, "get-audio-pad", i, &pad);
2786#if GST_VERSION_MAJOR < 1
2787                                        GstCaps* caps = gst_pad_get_negotiated_caps(pad);
2788#else
2789                                        GstCaps* caps = gst_pad_get_current_caps(pad);
2790#endif
2791                                        if(!caps)
2792                                                continue;
2793                                       
2794                                        GstStructure* str = gst_caps_get_structure(caps, 0);
2795                                        const gchar *g_type = gst_structure_get_name(str);
2796
2797                                        g_signal_emit_by_name(pipeline, "get-audio-tags", i, &tags);
2798
2799#if GST_VERSION_MAJOR < 1
2800                                        if(tags && gst_is_tag_list(tags))
2801#else
2802                                        if(tags && GST_IS_TAG_LIST(tags))
2803#endif
2804                                        {
2805                                                if(gst_tag_list_get_string(tags, GST_TAG_AUDIO_CODEC, &g_codec))
2806                                                {
2807                                                        printf("Audio Codec: %s\n", g_codec);
2808       
2809                                                        tmpstr = ostrcat(oitoa(i), ": ", 1, 0);
2810                                                        tmpstr = ostrcat(tmpstr, g_codec, 1, 0);
2811                                                        if(g_codec != NULL && g_type != NULL)
2812                                                                tmpstr = ostrcat(tmpstr, " (", 1, 0);
2813                                                        tmpstr = ostrcat(tmpstr, (gchar*)g_type, 1, 0);
2814                                                        if(g_codec != NULL && g_type != NULL)
2815                                                                tmpstr = ostrcat(tmpstr, ")", 1, 0);
2816
2817                                                        printf("Tracklist tmpstr: %s\n", tmpstr);
2818
2819                                                        TrackList[i * 2] = ostrcat(tmpstr, NULL, 0, 0);
2820                                                        g_free(tmpstr); tmpstr = NULL;
2821                                                        g_free(g_codec); g_codec = NULL;
2822                                                }
2823                                                if(gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &g_lang))
2824                                                {
2825                                                        printf("Audio Lang: %s\n", g_lang);
2826                                                        TrackList[(i * 2) + 1] = ostrcat(g_lang, NULL, 0, 0);
2827                                                        g_free(g_lang); g_lang = NULL;
2828                                                }
2829                                                gst_tag_list_free(tags);
2830                                        }
2831                                        else
2832                                        {
2833                                                printf("Audio Codec: %s\n", g_codec);
2834                                               
2835                                                tmpstr = ostrcat(oitoa(i), ": ", 1, 0);
2836                                                tmpstr = ostrcat(tmpstr, g_codec, 1, 0);
2837                                                if(g_codec != NULL && g_type != NULL)
2838                                                        tmpstr = ostrcat(tmpstr, " (", 1, 0);
2839                                                tmpstr = ostrcat(tmpstr, (gchar*)g_type, 1, 0);
2840                                                if(g_codec != NULL && g_type != NULL)
2841                                                        tmpstr = ostrcat(tmpstr, ")", 1, 0);
2842
2843                                                printf("Tracklist tmpstr: %s\n", tmpstr);                               
2844                                                TrackList[i * 2] = ostrcat(tmpstr, NULL, 0, 0);
2845
2846                                                g_free(tmpstr); tmpstr = NULL;
2847                                                g_free(g_codec); g_codec = NULL;
2848                                        }
2849                                }
2850                                break;
2851                        case 2:
2852                                for(i = 0; i < n_text; i++)
2853                                {
2854                                        GstTagList *tags = NULL;
2855                                        gchar *g_codec = NULL, *g_lang = NULL;
2856                                        GstPad* pad = 0;
2857                                        char* tmpstr = NULL;
2858
2859                                        g_signal_emit_by_name (pipeline, "get-text-pad", i, &pad);
2860                                        printf("SubTitle Type: %d\n", getSubtitleType(pad, g_codec));
2861
2862#if GST_VERSION_MAJOR < 1
2863                                        GstCaps* caps = gst_pad_get_negotiated_caps(pad);
2864#else
2865                                        GstCaps* caps = gst_pad_get_current_caps(pad);
2866#endif
2867                                        if (!caps && !g_codec)
2868                                        {
2869                                                caps = gst_pad_get_allowed_caps(pad);
2870                                        }
2871                                               
2872                                        GstStructure* str = gst_caps_get_structure(caps, 0);
2873                                        const gchar *g_type = gst_structure_get_name(str);
2874
2875                                        g_signal_emit_by_name(pipeline, "get-text-tags", i, &tags);
2876                                       
2877#if GST_VERSION_MAJOR < 1
2878                                        if (tags && gst_is_tag_list(tags))
2879#else
2880                                        if (tags && GST_IS_TAG_LIST(tags))
2881#endif
2882                                        {
2883                                                if(gst_tag_list_get_string(tags, GST_TAG_SUBTITLE_CODEC, &g_codec))
2884                                                {
2885                                                        printf("SubTitle Codec: %s\n", g_codec);
2886                                                        tmpstr = ostrcat(oitoa(i), ": ", 1, 0);
2887                                                        tmpstr = ostrcat(tmpstr, g_codec, 1, 0);
2888                                                        if(g_codec != NULL && g_type != NULL)
2889                                                                tmpstr = ostrcat(tmpstr, " (", 1, 0);
2890                                                        tmpstr = ostrcat(tmpstr, (gchar*)g_type, 1, 0);
2891                                                        if(g_codec != NULL && g_type != NULL)
2892                                                                tmpstr = ostrcat(tmpstr, ")", 1, 0);
2893
2894                                                        printf("Tracklist tmpstr: %s\n", tmpstr);
2895                                                        TrackList[i * 2] = ostrcat(tmpstr, NULL, 0, 0);
2896                                                        g_free(g_codec); g_codec = NULL;
2897                                                }
2898                                                if(gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &g_lang))
2899                                                {
2900                                                        printf("SubTitle Lang: %s\n", g_lang);
2901                                                        TrackList[(i * 2) + 1] = ostrcat(g_lang, NULL, 0, 0);
2902                                                        g_free(g_lang); g_lang = NULL;
2903                                                }
2904                                                gst_tag_list_free(tags);
2905                                        }
2906                                        else
2907                                        {
2908                                                printf("SubTitle Codec: %s\n", g_codec);
2909                                               
2910                                                tmpstr = ostrcat(oitoa(i), ": ", 1, 0);
2911                                                tmpstr = ostrcat(tmpstr, g_codec, 1, 0);
2912                                                if(g_codec != NULL && g_type != NULL)
2913                                                        tmpstr = ostrcat(tmpstr, " (", 1, 0);
2914                                                tmpstr = ostrcat(tmpstr, (gchar*)g_type, 1, 0);
2915                                                if(g_codec != NULL && g_type != NULL)
2916                                                        tmpstr = ostrcat(tmpstr, ")", 1, 0);
2917
2918                                                printf("Tracklist tmpstr: %s\n", tmpstr);               
2919                                                TrackList[i * 2] = ostrcat(tmpstr, NULL, 0, 0);
2920
2921                                                g_free(tmpstr); tmpstr = NULL;
2922                                                g_free(g_codec); g_codec = NULL;                               
2923                                        }
2924                                }
2925                                break;
2926                        default:
2927                                for(i = 0; i < n_video; i++)
2928                                {
2929                                        GstTagList *tags = NULL;
2930                                        gchar *g_codec = NULL, *g_lang = NULL;
2931                                       
2932                                        g_signal_emit_by_name(pipeline, "get-video-tags", i, &tags);
2933                                       
2934#if GST_VERSION_MAJOR < 1
2935                                        if (tags && gst_is_tag_list(tags))
2936#else
2937                                        if (tags && GST_IS_TAG_LIST(tags))
2938#endif
2939                                        {
2940                                                if(gst_tag_list_get_string(tags, GST_TAG_VIDEO_CODEC, &g_codec))
2941                                                {
2942                                                        printf("Video Codec: %s\n", g_codec);
2943                                                        TrackList[i * 2] = ostrcat(g_codec, NULL, 0, 0);
2944                                                        g_free(g_codec); g_codec = NULL;
2945                                                }
2946                                                if(gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &g_lang))
2947                                                {
2948                                                        printf("Video Lang: %s\n", g_lang);
2949                                                        TrackList[(i * 2) + 1] = ostrcat(g_lang, NULL, 0, 0);
2950                                                        g_free(g_lang); g_lang = NULL;
2951                                                }
2952                                                gst_tag_list_free(tags);
2953                                        }
2954                                }
2955                }
2956        }
2957#endif
2958//////////////////////////////NEUER CODE //////////////////////////////
2959
2960#ifdef EXTEPLAYER3
2961#ifdef EPLAYER3
2962        return TrackList2;
2963#else
2964        return TrackList;
2965#endif
2966#else
2967        return TrackList;
2968#endif
2969}
2970
2971//*CurTrackEncoding and *CurTrackName be freed
2972void playergetcurtrac(int type, int *CurTrackId, char** CurTrackEncoding, char** CurTrackName)
2973{
2974#ifdef EPLAYER3
2975        if(player && player->manager)
2976        {
2977                switch(type)
2978                {
2979                        case 1:
2980                                if(player->manager->audio)
2981                                {
2982                                        player->manager->audio->Command(player, MANAGER_GET, CurTrackId);
2983                                        player->manager->audio->Command(player, MANAGER_GETENCODING, CurTrackEncoding);
2984                                        player->manager->audio->Command(player, MANAGER_GETNAME, CurTrackName);
2985                                }
2986                                break;
2987                        case 2:
2988                                if(player->manager->subtitle)
2989                                {
2990                                        player->manager->subtitle->Command(player, MANAGER_GET, CurTrackId);
2991                                        player->manager->subtitle->Command(player, MANAGER_GETENCODING, CurTrackEncoding);
2992                                        player->manager->subtitle->Command(player, MANAGER_GETNAME, CurTrackName);
2993                                }
2994                                break;
2995                        default:
2996                                if(player->manager->video)
2997                                {
2998                                        player->manager->video->Command(player, MANAGER_GET, CurTrackId);
2999                                        player->manager->video->Command(player, MANAGER_GETENCODING, CurTrackEncoding);
3000                                        player->manager->video->Command(player, MANAGER_GETNAME, CurTrackName);
3001                                }
3002                }
3003
3004                if(CurTrackId != NULL)
3005                        debug(150, "Current Track ID: %d", *CurTrackId);
3006                if(*CurTrackEncoding != NULL)
3007                        debug(150, "Current Track Enc: %s", *CurTrackEncoding);
3008                if(*CurTrackName != NULL)
3009                        debug(150, "Current Track Name: %s", *CurTrackName);
3010        }
3011#endif
3012
3013#ifdef EPLAYER4
3014        if(pipeline != NULL)
3015        {
3016                switch(type)
3017                {
3018                        case 1:
3019                                g_object_get(G_OBJECT(pipeline), "current-audio", CurTrackId, NULL);
3020                                break;
3021                        case 2:
3022                                if(subtitleflag == 0)
3023                                        *CurTrackId = -1;
3024                                else
3025                                        g_object_get(G_OBJECT(pipeline), "current-text", CurTrackId, NULL);
3026                                break;
3027                }
3028                if(CurTrackId != NULL) {
3029                        debug(150, "Current Track ID: %d", *CurTrackId);
3030                }
3031        }
3032#endif
3033}
3034
3035unsigned long long playergetpts2()
3036{
3037        int64_t pts = 0;
3038        int64_t sec = 0;
3039        sec = 0;
3040
3041#ifdef EPLAYER3
3042        if(player && player->playback)
3043        {
3044                player->playback->Command(player, PLAYBACK_PTS, &pts);
3045                sec = pts / 90000;
3046                fprintf(stderr, "{\"J\":{\"ms\":%lld}}\n", pts / 90);
3047
3048                debug(150, "Pts = %02d:%02d:%02d (%lld sec)", (int)((sec / 60) / 60) % 60, (int)(sec / 60) % 60, (int)sec % 60, sec);
3049
3050        }
3051#endif
3052
3053        if(pts < 0) pts = 0;
3054        return pts;
3055}
3056
3057unsigned long long playergetpts()
3058{
3059#ifdef EXTEPLAYER3
3060#ifdef EPLAYER3
3061        int64_t pts = 0;
3062        int64_t sec = 0;
3063#else
3064        unsigned long long pts = 0;
3065        unsigned long long sec = 0;
3066#endif
3067#else
3068        unsigned long long pts = 0;
3069        unsigned long long sec = 0;
3070#endif
3071
3072#ifdef EPLAYER3
3073        if(player && player->playback)
3074        {
3075                player->playback->Command(player, PLAYBACK_PTS, &pts);
3076                sec = pts / 90000;
3077#ifdef EXTEPLAYER3
3078                debug(150, "Pts = %02d:%02d:%02d (%lld sec)", (int)((sec / 60) / 60) % 60, (int)(sec / 60) % 60, (int)sec % 60, sec);
3079#else
3080                debug(150, "Pts = %02d:%02d:%02d (%llu.0000 sec)", (int)((sec / 60) / 60) % 60, (int)(sec / 60) % 60, (int)sec % 60, sec);
3081#endif
3082        }
3083#endif
3084
3085#ifdef EPLAYER4
3086        GstFormat fmt = GST_FORMAT_TIME; //Returns time in nanosecs
3087       
3088/*
3089        if(pipeline)
3090        {
3091#if GST_VERSION_MAJOR < 1
3092                gst_element_query_position(pipeline, &fmt, (gint64*)&pts);
3093#else
3094                gst_element_query_position(pipeline, fmt, (gint64*)&pts);
3095#endif
3096                sec = pts / 1000000000;
3097                pts = sec * 90000;
3098                debug(150, "Pts = %02d:%02d:%02d (%llu.0000 sec)", (int)((sec / 60) / 60) % 60, (int)(sec / 60) % 60, (int)sec % 60, sec);
3099        }
3100*/
3101
3102        if(pipeline)
3103        {
3104                gint64 pos;
3105                GstElement *sink;
3106                pts = 0;
3107
3108                g_object_get(G_OBJECT (pipeline), "audio-sink", &sink, NULL);
3109
3110                if(!sink) g_object_get (G_OBJECT (pipeline), "video-sink", &sink, NULL);
3111                if(!sink) return 0;
3112
3113                gchar *name = gst_element_get_name(sink);
3114                gboolean use_get_decoder_time = ostrstr(name, "dvbaudiosink") || ostrstr(name, "dvbvideosink");
3115                g_free(name);
3116
3117                if(use_get_decoder_time) g_signal_emit_by_name(sink, "get-decoder-time", &pos);
3118
3119                gst_object_unref(sink);
3120
3121#if GST_VERSION_MAJOR < 1
3122                if(!use_get_decoder_time && !gst_element_query_position(pipeline, &fmt, &pos))
3123#else
3124                if(!use_get_decoder_time && !gst_element_query_position(pipeline, fmt, &pos))
3125#endif
3126                        return 0;
3127
3128                /* pos is in nanoseconds. we have 90 000 pts per second. */
3129                pts = pos / 11111;
3130                pts = pts - m_gst_startpts;
3131                sec = pts / 90000;
3132                debug(150, "StartPTS = %llu Pts = %02d:%02d:%02d (%llu.0000 sec)", m_gst_startpts, (int)((sec / 60) / 60) % 60, (int)(sec / 60) % 60, (int)sec % 60, sec);
3133        }
3134#endif
3135
3136        if(pts < 0) pts = 0;
3137        return pts;
3138}
3139
3140double playergetlength2()
3141{
3142        int64_t length = 0;
3143
3144#ifdef EPLAYER3
3145        if(player && player->playback)
3146        {
3147                player->playback->Command(player, PLAYBACK_LENGTH, (void*)&length);
3148                if(length < 0) length = 0;
3149                debug(150, "Length = %02d:%02d:%02d (%.4f sec)", (int)((length / 60) / 60) % 60, (int)(length / 60) % 60, (int)length % 60, length);
3150                debug(150, "Length2 = %02d:%02d:%02d (%lld sec)", (int)((length / 60) / 60) % 60, (int)(length / 60) % 60, (int)length % 60, length);
3151
3152                fprintf(stderr, "{\"PLAYBACK_LENGTH\":{\"length\":%lld}}\n", length);
3153
3154        }
3155#endif
3156
3157        return length;
3158}
3159
3160double playergetlength()
3161{
3162#ifdef EXTEPLAYER3
3163#ifdef EPLAYER3
3164        int64_t length = 0;
3165#else
3166        double length = 0;
3167#endif
3168#else
3169        double length = 0;
3170#endif
3171
3172#ifdef EPLAYER3
3173        if(player && player->playback)
3174        {
3175                player->playback->Command(player, PLAYBACK_LENGTH, &length);
3176                if(length < 0) length = 0;
3177#ifdef EXTEPLAYER3
3178                debug(150, "Length = %02d:%02d:%02d (%lld sec)", (int)((length / 60) / 60) % 60, (int)(length / 60) % 60, (int)length % 60, length);
3179#else
3180                debug(150, "Length = %02d:%02d:%02d (%.4f sec)", (int)((length / 60) / 60) % 60, (int)(length / 60) % 60, (int)length % 60, length);
3181#endif
3182        }
3183#endif
3184
3185#ifdef EPLAYER4
3186        GstFormat fmt = GST_FORMAT_TIME; //Returns time in nanosecs
3187        gint64 len;
3188
3189        if(pipeline)
3190        {
3191#if GST_VERSION_MAJOR < 1
3192                gst_element_query_duration(pipeline, &fmt, &len);
3193#else
3194                gst_element_query_duration(pipeline, fmt, &len);
3195#endif
3196                length = len / 1000000000;
3197                if(length < 0) length = 0;
3198                debug(150, "Length = %02d:%02d:%02d (%.4f sec)", (int)((length / 60) / 60) % 60, (int)(length / 60) % 60, (int)length % 60, length);
3199        }
3200#endif
3201
3202        return length;
3203}
3204
3205char* playergetinfo(char* tag)
3206{
3207        char* ret = NULL;
3208
3209#ifdef EPLAYER3
3210        char *tags[] = {"Title", "Artist", "Album", "Year", "Genre", "Comment", "Track", "Copyright", "TestLibEplayer", NULL};
3211        int i = 0;
3212
3213        if(player && player->playback)
3214        {
3215                while(tags[i] != NULL)
3216                {
3217                        ret = tags[i];
3218                        if(ostrcmp(tag, ret) == 0)
3219                        {
3220                                player->playback->Command(player, PLAYBACK_INFO, &ret);
3221                                break;
3222                        }
3223
3224                        i++;
3225                }
3226        }
3227#endif
3228        return ret;
3229}
3230
3231void playerchangeaudiotrack(int num)
3232{
3233        debug(150, "change audiotrac to %d\n", num);
3234
3235#ifdef EPLAYER3
3236        if(player && player->playback)
3237                player->playback->Command(player, PLAYBACK_SWITCH_AUDIO, (void*)&num);
3238#endif
3239
3240#ifdef EPLAYER4
3241        if(pipeline != NULL)
3242                g_object_set(G_OBJECT(pipeline), "current-audio", num, NULL);   
3243#endif
3244}
3245
3246void playerchangesubtitletrack(int num)
3247{
3248#ifdef EPLAYER3
3249        if(player && player->playback)
3250                player->playback->Command(player, PLAYBACK_SWITCH_SUBTITLE, (void*)&num);
3251#endif
3252
3253#ifdef EPLAYER4
3254        printf("player: set subtitle: %d\n", num);
3255        if(pipeline != NULL)
3256                g_object_set(G_OBJECT(pipeline), "current-text", num, NULL);
3257        subtitleflag = 1;       
3258#endif
3259}
3260
3261void playerstopsubtitletrack()
3262{
3263#ifdef EPLAYER3
3264        if(player && player->output && player->output->subtitle)
3265                player->output->subtitle->Command(player, (OutputCmd_t)OUTPUT_STOP, NULL);
3266#ifndef EXTEPLAYER3
3267        if(player && player->container && player->container->assContainer)
3268        {
3269                player->container->assContainer->Command(player, CONTAINER_STOP, NULL);
3270                player->container->assContainer->Command(player, CONTAINER_INIT, NULL);
3271        }
3272        if(player && player->manager && player->manager->subtitle)
3273        {
3274                int onlycurrent = 1;
3275                player->manager->subtitle->Command(player, MANAGER_DEL, (void*)&onlycurrent);
3276        }
3277#endif
3278#endif
3279
3280#ifdef EPLAYER4
3281        printf("player: stop subtitle\n");
3282        subtitleflag = 0;
3283        //if(pipeline != NULL)
3284        //      g_object_set(G_OBJECT(pipeline), "current-text", -1, NULL);
3285        if(subtitlethread != NULL)
3286                subtitlethread->aktion = STOP;
3287#endif
3288}
3289
3290int playerjumpts(struct service* servicenode, int sekunden, int *startpts, off64_t *poslastpts, off64_t *bitrate, int vpid, int tssize)
3291{
3292        int adaptation = 0;
3293        int payload = 0;
3294        int pes = 0;
3295        int tspid = 0;
3296       
3297        off64_t pts  = 0;
3298        uint64_t aktpts = 0;
3299        long long unsigned int lenpts = 0;
3300        long long unsigned int startpts1 = 0;
3301        long long unsigned int endpts = 0;
3302        long long unsigned int aktbitrate = 0;
3303        off64_t ziehlpts = 0;
3304
3305        off64_t curpos = 0;
3306        off64_t newpos = 0;
3307        off64_t jump = 0;
3308
3309        int kleiner = 0;
3310        int groesser = 0;
3311        int gleich = 0;
3312        int len = 0;
3313        int i = 0;
3314        int ret = 0;
3315
3316        if(servicenode == NULL) return -1;
3317
3318        int buflen = tssize * 15000;
3319        char *buf = malloc(buflen);
3320        if(buf == NULL)
3321                return -1;
3322       
3323        curpos = lseek64(servicenode->recsrcfd, 0, SEEK_CUR);   
3324        int dupfd = open(servicenode->recname, O_RDONLY | O_LARGEFILE);
3325        newpos = lseek64(dupfd, curpos, SEEK_SET);
3326       
3327        if (*startpts == 0)
3328        {
3329                if(videogetpts(status.aktservice->videodev, &aktpts) == 0)
3330                {
3331                                ziehlpts = (aktpts / 90000) + sekunden;
3332                }
3333                else
3334                        return 1;
3335        }
3336        else
3337        {
3338                ziehlpts = *startpts + sekunden;
3339        }
3340        *startpts = ziehlpts;
3341
3342        if(*bitrate == 0)
3343        {
3344                lenpts = servicenode->lenpts;
3345                startpts1 = servicenode->startpts;
3346                endpts = servicenode->endpts;
3347                aktbitrate = servicenode->bitrate;
3348                ret = gettsinfo(dupfd, &lenpts, &startpts1, &endpts, &aktbitrate, servicenode->tssize);
3349                if(ret != 0)
3350                {
3351                        err("can't read ts info");
3352                }
3353                else
3354                        *bitrate = aktbitrate;
3355                newpos = lseek64(dupfd, curpos, SEEK_SET);
3356        }
3357        else
3358                aktbitrate = *bitrate;
3359               
3360        if(*poslastpts == 0)
3361                *poslastpts = curpos;
3362       
3363        if(sekunden > 0)
3364        {
3365                err("not implemented");
3366                return 1;
3367        }       
3368        else if(sekunden < 0)
3369        {
3370                sekunden = sekunden * -1;
3371                if(aktbitrate != 0)
3372                {
3373                        jump = (aktbitrate / 8) * sekunden;
3374                        jump = jump + (curpos - *poslastpts);
3375                        jump = jump + (jump % servicenode->tssize);
3376                        newpos = lseek64(dupfd, -jump, SEEK_CUR);
3377                }
3378                else
3379                        newpos = lseek64(dupfd, - buflen, SEEK_CUR);
3380                if(newpos < 0)
3381                        newpos = lseek64(dupfd, tssize, SEEK_SET);
3382        }
3383        len = read(dupfd, buf, buflen);
3384        for(i = 0; i < len; i = i + 1)
3385        {
3386                if (buf[i] == 0x47 && buf[i+tssize] == 0x47)
3387                {
3388                        newpos = lseek64(dupfd, newpos + i, SEEK_SET);
3389                        break;
3390                }
3391        }
3392        if(i >= len)
3393        {
3394                newpos = lseek64(dupfd, curpos, SEEK_SET);     
3395                return 1;
3396        }
3397        while(1)
3398        {
3399        len = read(dupfd, buf, buflen);
3400
3401                if(len > 0)
3402                {
3403                        for(i = 0; i <= len-tssize; i = i + tssize)
3404                        {
3405                                payload = 0;
3406
3407                                tspid = (buf[i+1] & 0x1F) << 8;
3408                                tspid = tspid + (buf[i+2] & 0xFF);
3409                                pes = buf[i+1] & 0x40;
3410
3411                                if(tspid == vpid)
3412                                {       
3413                                        adaptation = buf[i+3] & 0x30;
3414                                        if(adaptation == 16)
3415                                        {
3416                                                payload = 4;
3417                                        }
3418                                        if(adaptation == 32)
3419                                        {
3420                                                //printf("adaptation field only\n");
3421                                        }
3422                                        if(adaptation == 48)
3423                                        {
3424                                                payload = buf[i+4] & 0xFF;
3425                                                payload = payload + 5;
3426                                        }
3427                                        if(payload != 0)
3428                                        {
3429                                                if(pes == 64)
3430                                                {
3431                                                        if(buf[i+payload+7] & 0x80) //PTS
3432                                                        {
3433                                                                pts = ((unsigned long long)(buf[i+payload+9] & 0xE)) << 29;
3434                                                                pts |= ((unsigned long long)(buf[i+payload+10] & 0xFF)) << 22;
3435                                                                pts |= ((unsigned long long)(buf[i+payload+11] & 0xFE)) << 14;
3436                                                                pts |= ((unsigned long long)(buf[i+payload+12] & 0xFF)) << 7;
3437                                                                pts |= ((unsigned long long)(buf[i+payload+13] & 0xFE)) >> 1;
3438                                                               
3439                                                                if(pts / 90000 == ziehlpts)
3440                                                                {
3441                                                                        gleich = newpos + i;
3442                                                                        break;
3443                                                                }
3444                                                                else if(pts / 90000 > ziehlpts)
3445                                                                {                                                                       
3446                                                                        groesser = newpos + i;
3447                                                                        break;
3448                                                                }
3449                                                                else
3450                                                                {
3451                                                                        kleiner = newpos + i;
3452                                                                }
3453                                                        }
3454                                                }
3455                                        }
3456                                }
3457                        }
3458                        if(gleich != 0)
3459                        {
3460                                close(dupfd);
3461                                free(buf);buf = NULL;
3462                                *poslastpts = lseek64(servicenode->recsrcfd, gleich, SEEK_SET);
3463                                return 0;
3464                        }
3465                        else if(groesser != 0 && kleiner != 0)
3466                        {
3467                                close(dupfd);
3468                                free(buf);buf = NULL;
3469                                *poslastpts = lseek64(servicenode->recsrcfd, kleiner, SEEK_SET);
3470                                return 0;
3471                        }
3472                        else if(groesser != 0)
3473                        {
3474                                if((newpos - buflen)  < 0)
3475                                {
3476                                        close(dupfd);
3477                                        free(buf);buf = NULL;
3478                                        *poslastpts = 0;
3479                                        return -1       ;
3480                                }
3481                                else
3482                                {
3483                                        newpos = lseek64(dupfd, -(buflen * 2), SEEK_CUR);
3484                                }
3485                        }
3486                }
3487                else
3488                {
3489                        if(kleiner == 0)
3490                        {
3491                                close(dupfd);
3492                                free(buf);buf = NULL;
3493                                newpos = lseek64(servicenode->recsrcfd, curpos, SEEK_SET);
3494                                *poslastpts = 0;
3495                                return -1;
3496                        }
3497                        else
3498                        {
3499                                close(dupfd);
3500                                free(buf);buf = NULL;
3501                                *poslastpts = lseek64(servicenode->recsrcfd, kleiner, SEEK_SET);
3502                                return 0;
3503                        }
3504                }
3505        }
3506}
3507
3508//praez = 1 .... sekunden
3509//                      =       2 .... zehntel
3510//                      = 3 .... hundertstel
3511//                      = 4 .... volle Uebereinstimmung
3512//
3513//type  = 0 .... alle
3514//                      = 1 .... nur PCR
3515//                      = 2 .... nur Video
3516//                      = 3 .... nur Audio
3517//
3518//flag = 0 --> play ts
3519//flag = 1 --> timeshift
3520//flag = 2 --> timeshift, not in play mode (only recording)
3521//flag = 9 --> dataset mode
3522//
3523off64_t playergetptspos(unsigned long long fpts, off64_t pos, int dir, int praez, int type, int flag, char* dsn)
3524{
3525        unsigned long long pts;
3526        int ret = 0, dupfd = -1, left = 0, tssize = 0, recbsize = 0;
3527        unsigned char* buf = NULL;
3528        unsigned char *payload;
3529        int pid = 0, pusi = 0;
3530        unsigned char* packet;
3531        struct service* snode;
3532       
3533        if(type > 3)
3534        {
3535                printf("type %i nicht unterstützt\n", type);
3536                return -1;
3537        }
3538       
3539        if(flag == 2)
3540                snode = getservice(RECORDTIMESHIFT, 0);
3541        else if(flag != 9)
3542                snode = getservice(RECORDPLAY, 0);
3543               
3544        if(flag == 9)
3545        {
3546                tssize = 188;
3547                recbsize = tssize * 1024 * 10;
3548                dupfd = open(dsn, O_RDONLY | O_LARGEFILE );
3549        }
3550        else
3551        {
3552                tssize = snode->tssize;
3553                recbsize = snode->tssize * 1024 * 10;
3554                dupfd = open(snode->recname, O_RDONLY | O_LARGEFILE);
3555        }
3556
3557        if(dupfd < 0)
3558        {
3559                err("copy source fd not ok");
3560                return -1;
3561        }
3562
3563        buf = malloc(recbsize);
3564        if(buf == NULL)
3565        {
3566                err("no mem");
3567                return -1;
3568        }
3569        packet = buf;
3570        if(dir > 0) 
3571                pos = lseek64(dupfd, pos, SEEK_SET);
3572        else
3573                pos = lseek64(dupfd, pos - recbsize, SEEK_SET);
3574       
3575        ret = read(dupfd,  buf, recbsize);
3576        close(dupfd);
3577        left = 0;
3578       
3579        if(buf[0] != 0x47)
3580        {
3581                while(left < tssize)
3582                {
3583                        if(buf[left] == 0x47) break;
3584                        left++;
3585                }
3586                if(left >= tssize)
3587                {
3588                        free(buf);
3589                        return -1;
3590                }       
3591        }
3592        pts = 0;
3593        while(left <= recbsize - tssize)
3594        {
3595                if(pts != 0)
3596                {
3597                        switch( praez )
3598          {
3599        case 1 :        if(fpts / 90000 != pts / 90000)
3600                                                        pts = 0;
3601                                                break;
3602        case 2 :        if(fpts / 9000 != pts / 9000)
3603                                                        pts = 0;
3604                                                break;
3605        case 3 :        if(fpts / 900 != pts / 900)
3606                                                        pts = 0;
3607                                                break;         
3608        case 4 :        if(fpts != pts )
3609                                                        pts = 0;
3610                                                break;
3611                                default :       free(buf); return -1; break;
3612                        }
3613                        if(pts != 0)
3614                        {       
3615                                pos = pos + left - tssize;
3616                                free(buf);
3617                                return pos;
3618                        }
3619                }
3620                packet = buf + left;
3621                left = left + tssize;
3622                                               
3623                pid = ((packet[1] << 8) | packet[2]) & 0x1FFF;
3624                pusi = !!(packet[1] & 0x40);
3625                //check for adaption field
3626                if(packet[3] & 0x20)
3627                {
3628                        if(type > 1)continue;
3629                        if(packet[4] >= 183) continue;
3630                        if(packet[4])
3631                        {
3632                                if(packet[5] & 0x10) //PCR present
3633                                {
3634                                        pts = ((unsigned long long)(packet[6] & 0xFF)) << 25;
3635                                        pts |= ((unsigned long long)(packet[7] & 0xFF)) << 17;
3636                                        pts |= ((unsigned long long)(packet[8] & 0xFE)) << 9;
3637                                        pts |= ((unsigned long long)(packet[9] & 0xFF)) << 1;
3638                                        pts |= ((unsigned long long)(packet[10] & 0x80)) >> 7;
3639                                        continue;
3640                                }
3641                        }
3642                        payload = packet + packet[4] + 4 + 1;
3643                } else
3644                        payload = packet + 4;
3645               
3646                if(type == 1) continue;
3647                if(!pusi) continue;
3648               
3649                if (payload[0] || payload[1] || (payload[2] != 1))
3650                        continue;
3651               
3652                        //stream use extension mechanism def in ISO 13818-1 Amendment 2
3653                if(payload[3] == 0xFD)
3654                {
3655                        if(payload[7] & 1) //PES extension flag
3656                        {
3657                                int offs = 0;
3658                                if(payload[7] & 0x80) offs += 5; //pts avail
3659                                if(payload[7] & 0x40) offs += 5; //dts avail
3660                                if(payload[7] & 0x20) offs += 6; //escr avail
3661                                if(payload[7] & 0x10) offs += 3; //es rate
3662                                if(payload[7] & 0x8) offs += 1; //dsm trickmode
3663                                if(payload[7] & 0x4) offs += 1; //additional copy info
3664                                if(payload[7] & 0x2) offs += 2; //crc
3665                                if(payload[8] < offs) continue;
3666
3667                                uint8_t pef = payload[9 + offs++]; //pes extension field
3668                                if(pef & 1) //pes extension flag 2
3669                                {
3670                                        if(pef & 0x80) offs += 16; //private data flag
3671                                        if(pef & 0x40) offs += 1; //pack header field flag
3672                                        if(pef & 0x20) offs += 2; //program packet sequence counter flag
3673                                        if(pef & 0x10) offs += 2; //P-STD buffer flag
3674                                        if(payload[8] < offs) continue;
3675
3676                                        uint8_t stream_id_extension_len = payload[9 + offs++] & 0x7F;
3677                                        if(stream_id_extension_len >= 1)
3678                                        {
3679                                                if(payload[8] < (offs + stream_id_extension_len)) continue;
3680                                                //stream_id_extension_bit (should not set)
3681                                                if(payload[9 + offs] & 0x80) continue;
3682                                                switch(payload[9 + offs])
3683                                                {
3684                                                        case 0x55 ... 0x5f: break; //VC-1
3685                                                        case 0x71: break; //AC3 / DTS
3686                                                        case 0x72: break; //DTS - HD
3687                                                        default:
3688                                                                printf("skip unknwn stream_id_extension %02x\n", payload[9 + offs]);
3689                                                                continue;
3690                                                }
3691                                        }
3692                                        else
3693                                                continue;
3694                                }
3695                                else
3696                                        continue;
3697                        }
3698                        else
3699                                continue;
3700                }
3701                //drop non-audio, non-video packets because other streams
3702                //can be non-compliant.
3703                //0xC0 = audio, 0xE0 = video
3704                else if(((payload[3] & 0xE0) != 0xC0) && ((payload[3] & 0xF0) != 0xE0))
3705                        continue;
3706
3707                if((payload[7] & 0x80) && ((payload[3] & 0xF0) != 0xE0) && (type == 0 || type == 2)) //PTS video
3708                {
3709                        pts = ((unsigned long long)(payload[9] & 0xE)) << 29;
3710                        pts |= ((unsigned long long)(payload[10] & 0xFF)) << 22;
3711                        pts |= ((unsigned long long)(payload[11] & 0xFE)) << 14;
3712                        pts |= ((unsigned long long)(payload[12] & 0xFF)) << 7;
3713                        pts |= ((unsigned long long)(payload[13] & 0xFE)) >> 1;
3714                        continue;
3715                }
3716                if((payload[7] & 0x80) && ((payload[3] & 0xE0) != 0xC0) && (type == 0 || type == 3)) //PTS audio
3717                {
3718                        pts = ((unsigned long long)(payload[9] & 0xE)) << 29;
3719                        pts |= ((unsigned long long)(payload[10] & 0xFF)) << 22;
3720                        pts |= ((unsigned long long)(payload[11] & 0xFE)) << 14;
3721                        pts |= ((unsigned long long)(payload[12] & 0xFF)) << 7;
3722                        pts |= ((unsigned long long)(payload[13] & 0xFE)) >> 1;
3723                        continue;
3724                }
3725        }
3726        free(buf);
3727        return recbsize * -1;
3728}
3729
3730#ifdef EPLAYER4
3731/* Extract some metadata from the streams and print it on the screen */
3732static void analyze_streams(CustomData *data)
3733{
3734        gint i;
3735        GstTagList *tags;
3736        gchar *str;
3737        guint rate;
3738
3739        /* Read some properties */
3740        g_object_get(pipeline, "n-video", &data->n_video, NULL);
3741        g_object_get(pipeline, "n-audio", &data->n_audio, NULL);
3742        g_object_get(pipeline, "n-text", &data->n_text, NULL);
3743
3744        g_print("%d video stream(s), %d audio stream(s), %d text stream(s)\n", data->n_video, data->n_audio, data->n_text);
3745
3746        g_print ("\n");
3747        for(i = 0; i < data->n_video; i++)
3748        {
3749                tags = NULL;
3750                /* Retrieve the stream's video tags */
3751                g_signal_emit_by_name(pipeline, "get-video-tags", i, &tags);
3752                if(tags)
3753                {
3754                        g_print("video stream %d:\n", i);
3755                        gst_tag_list_get_string(tags, GST_TAG_VIDEO_CODEC, &str);
3756                        g_print("  codec: %s\n", str ? str : "unknown");
3757                        g_free(str);
3758                        gst_tag_list_free(tags);
3759                }
3760        }
3761
3762        g_print("\n");
3763        for(i = 0; i < data->n_audio; i++)
3764        {
3765                tags = NULL;
3766                g_signal_emit_by_name(pipeline, "get-audio-tags", i, &tags);
3767                if(tags)
3768                {
3769                        /* Retrieve the stream's audio tags */
3770                        g_print("audio stream %d:\n", i);
3771                        if(gst_tag_list_get_string (tags, GST_TAG_AUDIO_CODEC, &str))
3772                        {
3773                                g_print("  codec: %s\n", str);
3774                                g_free(str);
3775                        }
3776                        if(gst_tag_list_get_string (tags, GST_TAG_LANGUAGE_CODE, &str))
3777                        {
3778                                g_print("  language: %s\n", str);
3779                                g_free(str);
3780                        }
3781                        if(gst_tag_list_get_uint (tags, GST_TAG_BITRATE, &rate))
3782                        {
3783                                g_print("  bitrate: %d\n", rate);
3784                        }
3785                        gst_tag_list_free(tags);
3786                }
3787        }
3788
3789        g_print("\n");
3790        for(i = 0; i < data->n_text; i++)
3791        {
3792                tags = NULL;
3793                /* Retrieve the stream's subtitle tags */
3794                g_print("subtitle stream %d:\n", i);
3795                g_signal_emit_by_name(pipeline, "get-text-tags", i, &tags);
3796                if(tags)
3797                {
3798                        if(gst_tag_list_get_string (tags, GST_TAG_LANGUAGE_CODE, &str))
3799                        {
3800                                g_print("  language: %s\n", str);
3801                                g_free(str);
3802                        }
3803                        gst_tag_list_free(tags);
3804                }
3805                else
3806                {
3807                        g_print("  no tags found\n");
3808                }
3809        }
3810
3811        g_object_get(pipeline, "current-video", &data->current_video, NULL);
3812        g_object_get(pipeline, "current-audio", &data->current_audio, NULL);
3813        g_object_get(pipeline, "current-text", &data->current_text, NULL);
3814
3815        g_print("\n");
3816        g_print("Currently playing video stream %d, audio stream %d and subtitle stream %d\n", data->current_video, data->current_audio, data->current_text);
3817        g_print("Type any number and hit ENTER to select a different subtitle stream\n");
3818}
3819#endif
3820
3821#ifdef EPLAYER4
3822void playersend_ff_fr_event(gdouble rate) {
3823        gint64 position;
3824        GstFormat format = GST_FORMAT_TIME;
3825        GstEvent *seek_event;
3826   
3827        /* Obtain the current position, needed for the seek event */
3828#if GST_VERSION_MAJOR < 1
3829        if (!gst_element_query_position (pipeline, &format, &position)) {
3830#else
3831        if (!gst_element_query_position (pipeline, format, &position)) {
3832#endif
3833                g_printerr ("Unable to retrieve current position.\n");
3834                return;
3835        }
3836   
3837        /* Create the seek event */
3838        if (rate > 0)
3839        {       
3840                seek_event = gst_event_new_seek (rate, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE,GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, 0);
3841  }
3842        else
3843        {
3844                seek_event = gst_event_new_seek (rate, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE,GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, position);
3845        }
3846   
3847        if (video_sink == NULL) {
3848                /* If we have not done so, obtain the sink through which we will send the seek events */
3849                g_object_get (pipeline, "video-sink", &video_sink, NULL);
3850        }
3851   
3852        /* Send the event */
3853        gst_element_send_event (video_sink, seek_event);
3854   
3855        g_print ("Current rate: %g\n", rate);
3856}
3857#endif
3858
3859#ifdef EXTEPLAYER3
3860char* getsubtext()
3861{
3862        char* tmpstr = NULL;
3863        if(player && player->container && player->container->selectedContainer)
3864                player->container->selectedContainer->Command(player, CONTAINER_GET_SUBTEXT, (void*)&tmpstr);
3865
3866//      if(subtitlethread == NULL)
3867                subtitlethread = addtimer(&playersubtitle_thread, START, 10000, 1, (void*)tmpstr, NULL, NULL);
3868
3869        return subtext;
3870}
3871#endif
3872
3873#endif
Note: See TracBrowser for help on using the repository browser.