1 /*****************************************************************************
2  * get_pcr_pid.c: stdout the PID of the PCR of a given program
3  *****************************************************************************
4  * Copyright (C) 2009-2011 VideoLAN
5  * $Id: pcread.c 15 2006-06-15 22:17:58Z cmassiot $
6  *
7  * Authors: Christophe Massiot <massiot@via.ecp.fr>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22  *****************************************************************************/
23 
24 #include "config.h"
25 
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <stdbool.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <sys/types.h>
33 #include <fcntl.h>
34 
35 #if defined(HAVE_INTTYPES_H)
36 #include <inttypes.h>
37 #elif defined(HAVE_STDINT_H)
38 #include <stdint.h>
39 #endif
40 
41 /* The libdvbpsi distribution defines DVBPSI_DIST */
42 #ifdef DVBPSI_DIST
43 #include "../src/dvbpsi.h"
44 #include "../src/descriptor.h"
45 #include "../src/demux.h"
46 #include "../src/tables/pat.h"
47 #include "../src/tables/pmt.h"
48 #include "../src/psi.h"
49 #else
50 #include <dvbpsi/dvbpsi.h>
51 #include <dvbpsi/descriptor.h>
52 #include <dvbpsi/demux.h>
53 #include <dvbpsi/pat.h>
54 #include <dvbpsi/pmt.h>
55 #include <dvbpsi/psi.h>
56 #endif
57 
58 /*****************************************************************************
59  * Local declarations
60  *****************************************************************************/
61 #define READ_ONCE 100
62 #define MAX_PROGRAMS 25
63 #define TS_SIZE 188
64 
65 static int i_fd = -1;
66 static int i_ts_read = 0;
67 static dvbpsi_t *p_pat_dvbpsi_fd;
68 static int i_nb_programs = 0;
69 static uint16_t i_program = 0;
70 static uint16_t pi_pmt_pids[MAX_PROGRAMS];
71 static dvbpsi_t *p_pmt_dvbpsi_fds[MAX_PROGRAMS];
72 
73 /*****************************************************************************
74  * DVBPSI messaging callback
75  *****************************************************************************/
message(dvbpsi_t * handle,const dvbpsi_msg_level_t level,const char * msg)76 static void message(dvbpsi_t *handle, const dvbpsi_msg_level_t level, const char* msg)
77 {
78     switch(level)
79     {
80         case DVBPSI_MSG_ERROR: fprintf(stderr, "Error: "); break;
81         case DVBPSI_MSG_WARN:  fprintf(stderr, "Warning: "); break;
82         case DVBPSI_MSG_DEBUG: fprintf(stderr, "Debug: "); break;
83         default: /* do nothing */
84             return;
85     }
86     fprintf(stderr, "%s\n", msg);
87 }
88 
89 /*****************************************************************************
90  * PMTCallback
91  *****************************************************************************/
PMTCallback(void * _unused,dvbpsi_pmt_t * p_pmt)92 static void PMTCallback( void *_unused, dvbpsi_pmt_t *p_pmt )
93 {
94     if ( p_pmt->i_program_number != i_program )
95     {
96         dvbpsi_pmt_delete( p_pmt );
97         return;
98     }
99 
100     printf( "%u\n", p_pmt->i_pcr_pid );
101     close( i_fd );
102     exit(EXIT_SUCCESS);
103 }
104 
105 /*****************************************************************************
106  * PATCallback
107  *****************************************************************************/
PATCallback(void * _unused,dvbpsi_pat_t * p_pat)108 static void PATCallback( void *_unused, dvbpsi_pat_t *p_pat )
109 {
110     dvbpsi_pat_program_t *p_program;
111 
112     if (i_nb_programs >= MAX_PROGRAMS)
113     {
114         fprintf(stderr, "Too many PMT programs\n");
115         dvbpsi_pat_delete( p_pat );
116         return;
117     }
118 
119     for( p_program = p_pat->p_first_program; p_program != NULL && i_nb_programs < MAX_PROGRAMS;
120          p_program = p_program->p_next )
121     {
122         if( p_program->i_number != 0
123              && (!i_program || i_program == p_program->i_number) )
124         {
125             pi_pmt_pids[i_nb_programs] = p_program->i_pid;
126             p_pmt_dvbpsi_fds[i_nb_programs] = dvbpsi_new(&message, DVBPSI_MSG_DEBUG);
127             if (p_pmt_dvbpsi_fds[i_nb_programs])
128             {
129                 if (dvbpsi_pmt_attach(p_pmt_dvbpsi_fds[i_nb_programs],
130                                       p_program->i_number, PMTCallback, NULL))
131                     i_nb_programs++;
132             }
133         }
134     }
135 
136     dvbpsi_pat_delete( p_pat );
137 }
138 
139 /*****************************************************************************
140  * TSHandle: find and decode PSI
141  *****************************************************************************/
ts_GetPID(const uint8_t * p_ts)142 static inline uint16_t ts_GetPID( const uint8_t *p_ts )
143 {
144     return (((uint16_t)p_ts[1] & 0x1f) << 8) | p_ts[2];
145 }
146 
ts_CheckSync(const uint8_t * p_ts)147 static inline int ts_CheckSync( const uint8_t *p_ts )
148 {
149     return p_ts[0] == 0x47;
150 }
151 
TSHandle(uint8_t * p_ts)152 static void TSHandle( uint8_t *p_ts )
153 {
154     uint16_t i_pid = ts_GetPID( p_ts );
155     int i;
156 
157     if ( !ts_CheckSync( p_ts ) )
158     {
159         fprintf( stderr, "lost TS synchro, go and fix your file "
160 #if defined(WIN32)
161                  " (pos=%u)\n",  (uint32_t) i_ts_read * TS_SIZE
162 #else
163                  " (pos=%ju)\n", (uintmax_t)i_ts_read * TS_SIZE
164 #endif
165 	);
166         exit(EXIT_FAILURE);
167     }
168 
169     if ( i_pid == 0 && !i_nb_programs )
170     {
171         dvbpsi_packet_push( p_pat_dvbpsi_fd, p_ts );
172     }
173 
174     for ( i = 0; i < i_nb_programs; i++ )
175     {
176         if ( pi_pmt_pids[i] == i_pid )
177             dvbpsi_packet_push( p_pmt_dvbpsi_fds[i], p_ts );
178     }
179 }
180 
181 /*****************************************************************************
182  * Entry point
183  *****************************************************************************/
main(int i_argc,char ** pp_argv)184 int main( int i_argc, char **pp_argv )
185 {
186     uint8_t *p_buffer;
187     int result = EXIT_FAILURE;
188 
189     if ( i_argc < 2 || i_argc > 3 || !strcmp( pp_argv[1], "-" ) )
190     {
191         fprintf( stderr, "Usage: get_pcr_pid <input ts> [<program number>]\n" );
192         exit(EXIT_FAILURE);
193     }
194 
195     if ( (i_fd = open( pp_argv[1], O_RDONLY )) == -1 )
196     {
197         fprintf( stderr, "open(%s) failed (%s)\n", pp_argv[1],
198                  strerror(errno) );
199         exit(EXIT_FAILURE);
200     }
201 
202     if ( i_argc == 3 )
203         i_program = strtol( pp_argv[2], NULL, 0 );
204 
205     p_pat_dvbpsi_fd = dvbpsi_new(&message, DVBPSI_MSG_DEBUG);
206     if (p_pat_dvbpsi_fd == NULL)
207         goto out;
208 
209     if (!dvbpsi_pat_attach(p_pat_dvbpsi_fd, PATCallback, NULL ))
210         goto out;
211 
212     p_buffer = malloc( TS_SIZE * READ_ONCE );
213     if (p_buffer == NULL)
214         goto out;
215 
216     for ( ; ; )
217     {
218         int i;
219         ssize_t i_ret;
220 
221         if ( (i_ret = read( i_fd, p_buffer, TS_SIZE * READ_ONCE )) < 0 )
222         {
223             fprintf( stderr, "read error (%s)\n", strerror(errno) );
224             break;
225         }
226         if ( i_ret == 0 )
227         {
228             fprintf( stderr, "end of file reached\n" );
229             break;
230         }
231 
232         for ( i = 0; i < i_ret / TS_SIZE; i++ )
233         {
234             TSHandle( p_buffer + TS_SIZE * i );
235             i_ts_read++;
236         }
237     }
238     free( p_buffer );
239 
240     for( int i = 0; i < MAX_PROGRAMS; i++)
241     {
242         if (p_pmt_dvbpsi_fds[i])
243         {
244             dvbpsi_pmt_detach(p_pmt_dvbpsi_fds[i]);
245             dvbpsi_delete(p_pmt_dvbpsi_fds[i]);
246         }
247         p_pmt_dvbpsi_fds[i] = NULL;
248     }
249     result = EXIT_SUCCESS;
250 
251 out:
252     if (p_pat_dvbpsi_fd)
253     {
254       dvbpsi_pat_detach(p_pat_dvbpsi_fd);
255       dvbpsi_delete(p_pat_dvbpsi_fd);
256     }
257     close( i_fd );
258 
259     return result;
260 }
261