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