kopia lustrzana https://github.com/F5OEO/tstools
				
				
				
			Changes to allow tsserve to serve all the original TS data to
a client, rather than just the PES for video/audio. --HG-- extra : convert_revision : svn%3Aeff31bef-be4a-0410-a8fe-e47997df2690/trunk%4017issue20
							rodzic
							
								
									18acac0c76
								
							
						
					
					
						commit
						7a02df44f7
					
				
							
								
								
									
										87
									
								
								pes.c
								
								
								
								
							
							
						
						
									
										87
									
								
								pes.c
								
								
								
								
							|  | @ -38,6 +38,7 @@ | |||
| #include "pes_fns.h" | ||||
| #include "pidint_fns.h" | ||||
| #include "h262_fns.h" | ||||
| #include "tswrite_fns.h" | ||||
| #include "misc_fns.h" | ||||
| 
 | ||||
| //#define DEBUG
 | ||||
|  | @ -1366,6 +1367,7 @@ static int read_next_PES_packet_from_TS(PES_reader_p       reader, | |||
|   for (;;) | ||||
|   { | ||||
|     int     err; | ||||
|     byte   *ts_packet; | ||||
|     int     payload_unit_start_indicator; | ||||
|     byte   *adapt; | ||||
|     int     adapt_len; | ||||
|  | @ -1377,14 +1379,21 @@ static int read_next_PES_packet_from_TS(PES_reader_p       reader, | |||
|     // Remember the position of the packet we're going to read
 | ||||
|     reader->posn = reader->tsreader->posn; | ||||
| 
 | ||||
|     // Read the next packet
 | ||||
|     err = get_next_TS_packet(reader->tsreader,&pid, | ||||
|                              &payload_unit_start_indicator, | ||||
|                              &adapt,&adapt_len,&payload,&payload_len); | ||||
|     // And read it
 | ||||
|     // Remember that `ts_packet` will not persist, as it is a pointer
 | ||||
|     // into the TS buffering innards
 | ||||
|     err = read_next_TS_packet(reader->tsreader,&ts_packet); | ||||
|     if (err == EOF) | ||||
|     { | ||||
|       // Check for an unbounded (length indicated as zero) video stream
 | ||||
|       // with a PES packet outstanding
 | ||||
|       // If we've been given EOF, then either we're just *read* EOF
 | ||||
|       // instead of a packet (the obvious case), or we read some data
 | ||||
|       // that was terminated by EOF last time, and the EOF was "deferred"
 | ||||
|       // by the underlying buffering methods.
 | ||||
|       // So, just in case, we'll check for an unbounded (length marked as
 | ||||
|       // zero) video stream PES packet
 | ||||
|       // XXX Note that an unbounded packet will thus not be correctly written
 | ||||
|       // XXX out when we've been asked to write_TS_packets -- fix this if it
 | ||||
|       // XXX ever becomes a problem
 | ||||
|       check_for_EOF_packet(reader,packet_data); | ||||
|       if (*packet_data == NULL) | ||||
|         return EOF; | ||||
|  | @ -1397,6 +1406,29 @@ static int read_next_PES_packet_from_TS(PES_reader_p       reader, | |||
|               reader->posn); | ||||
|       return 1; | ||||
|     } | ||||
|     err = split_TS_packet(ts_packet,&pid,&payload_unit_start_indicator, | ||||
|                           &adapt,&adapt_len,&payload,&payload_len); | ||||
|     if (err) | ||||
|     { | ||||
|       fprintf(stderr,"### Error interpreting TS packet at " OFFSET_T_FORMAT "\n", | ||||
|               reader->posn); | ||||
|       return 1; | ||||
|     } | ||||
| 
 | ||||
|     // If we're writing out TS packets directly to a client, then this
 | ||||
|     // is probably a sensible place to do it.
 | ||||
|     if (reader->write_TS_packets && reader->tswriter != NULL && | ||||
|         !reader->suppress_writing) | ||||
|     { | ||||
|       err = tswrite_write(reader->tswriter,ts_packet,pid,FALSE,0); | ||||
|       if (err) | ||||
|       { | ||||
|         fprintf(stderr,"### Error writing TS packet (PID %04x) at " | ||||
|                 OFFSET_T_FORMAT "\n",pid,reader->posn); | ||||
|         return 1; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| #if DEBUG_PES_ASSEMBLY | ||||
|     printf("@@@ TS packet at " OFFSET_T_FORMAT " with pid %3x", | ||||
|  | @ -1467,7 +1499,7 @@ static int read_next_PES_packet_from_TS(PES_reader_p       reader, | |||
|       free(reader->pmt_data); | ||||
|       reader->pmt_data = NULL; reader->pmt_data_len = reader->pmt_data_used = 0; | ||||
| 
 | ||||
|       if (reader->write_PES_packets) | ||||
|       if (reader->write_PES_packets && !reader->suppress_writing) | ||||
|       { | ||||
|         // XXX We *probably* should check if it's changed before doing this,
 | ||||
|         //     but at least by outputting it again we ensure it's current
 | ||||
|  | @ -1688,6 +1720,8 @@ static int build_PES_reader_datastructure(int            give_info, | |||
| 
 | ||||
|   new->tswriter = NULL; | ||||
|   new->write_PES_packets = FALSE; | ||||
|   new->write_TS_packets = FALSE; | ||||
|   new->suppress_writing = TRUE; | ||||
|   new->dont_write_current_packet = FALSE; | ||||
|   new->pes_padding = 0; | ||||
| 
 | ||||
|  | @ -2293,6 +2327,7 @@ extern int read_next_PES_packet(PES_reader_p  reader) | |||
|   if (reader->packet != NULL) | ||||
|   { | ||||
|     if (reader->write_PES_packets && reader->tswriter != NULL && | ||||
|         !reader->suppress_writing && | ||||
|         !reader->dont_write_current_packet) | ||||
|     { | ||||
|       // Aha - we need to output the previous PES packet
 | ||||
|  | @ -3579,34 +3614,42 @@ extern int find_ESCR_in_PES(byte      data[], | |||
| // Server support
 | ||||
| // ============================================================
 | ||||
| /*
 | ||||
|  * Prepare for PES packets being written out to a TS writer, and | ||||
|  * request that they be written out. | ||||
|  * Packets can be written out to a client via a TS writer, as a | ||||
|  * "side effect" of reading them. The original mechanism was to | ||||
|  * write out PES packets (as TS) as they are read. This will work | ||||
|  * for PS or TS data, and writes out only those PES packets that | ||||
|  * have been read for video or audio data. | ||||
|  * | ||||
|  * The effect is that, each time a new PES packet is read in, it will | ||||
|  * be written out to the TS output stream. | ||||
|  * An alternative, which will only work for TS input data, is | ||||
|  * to write out TS packets as they are read. This will write all | ||||
|  * TS packets to the client. | ||||
|  * | ||||
|  * - `reader` is our PES reader context | ||||
|  * - `tswriter` is the TS writer | ||||
|  * - if `write_PES`, then write PES packets out as they are read from | ||||
|  *   the input, otherwise write TS packets. | ||||
|  * - `program_freq` is how often to write out program data (PAT/PMT) | ||||
|  *   if we are writing PES data (if we are writing TS data, then the | ||||
|  *   program data will be in the original TS packets) | ||||
|  */ | ||||
| extern void set_server_output(PES_reader_p  reader, | ||||
|                               TS_writer_p   tswriter, | ||||
|                               int           write_PES, | ||||
|                               int           program_freq) | ||||
| { | ||||
|   reader->tswriter = tswriter; | ||||
|   reader->program_freq = program_freq; | ||||
|   reader->program_index = 0; | ||||
|   reader->write_PES_packets = TRUE; | ||||
|   reader->write_PES_packets = write_PES; | ||||
|   reader->write_TS_packets = !write_PES; | ||||
|   reader->suppress_writing = FALSE; | ||||
|   return; | ||||
| } | ||||
|  | ||||
| /*
 | ||||
|  * Start PES packets being written out to a TS writer (again). | ||||
|  * Start packets being written out to a TS writer (again). | ||||
|  * | ||||
|  * The effect is that, each time a new PES packet is read in, it will | ||||
|  * be written out to the TS output stream. | ||||
|  * | ||||
|  * If PES packets were already being written out, this does nothing. | ||||
|  * If packets were already being written out, this does nothing. | ||||
|  * | ||||
|  * If set_server_output() has not been called to define a TS writer | ||||
|  * context, this will have no effect. | ||||
|  | @ -3616,21 +3659,21 @@ extern void set_server_output(PES_reader_p  reader, | |||
| extern void start_server_output(PES_reader_p  reader) | ||||
| { | ||||
|   if (reader != NULL) | ||||
|     reader->write_PES_packets = TRUE; | ||||
|     reader->suppress_writing = FALSE; | ||||
|   return; | ||||
| } | ||||
|  | ||||
| /*
 | ||||
|  * Stop PES packets being written out to a TS writer. | ||||
|  * Stop packets being written out to a TS writer. | ||||
|  * | ||||
|  * If PES packets were already not being written out, this does nothing. | ||||
|  * If packets were already not being written out, this does nothing. | ||||
|  * | ||||
|  * If `reader` is NULL, nothing is done. | ||||
|  */ | ||||
| extern void stop_server_output(PES_reader_p  reader) | ||||
| { | ||||
|   if (reader != NULL) | ||||
|     reader->write_PES_packets = FALSE; | ||||
|     reader->suppress_writing = TRUE; | ||||
|   return; | ||||
| } | ||||
|  | ||||
|  | @ -3644,6 +3687,8 @@ extern void stop_server_output(PES_reader_p  reader) | |||
|  * the recipient, as the extra data (which has an irrelevant stream id) | ||||
|  * will be ignored by the video processor, but not by preceding systems. | ||||
|  * | ||||
|  * This does nothing if TS packets are being output directly. | ||||
|  * | ||||
|  * - `reader` is our PES reader context | ||||
|  * - `extra` is how many extra packets to output per "real" packet. | ||||
|  */ | ||||
|  |  | |||
							
								
								
									
										11
									
								
								pes_defns.h
								
								
								
								
							
							
						
						
									
										11
									
								
								pes_defns.h
								
								
								
								
							|  | @ -200,6 +200,17 @@ struct PES_reader | |||
|   // with an irrelevant stream id).
 | ||||
|   int		    pes_padding; | ||||
| 
 | ||||
|   // If the original data is TS, and we want to send *all* of said data
 | ||||
|   // to the server, it is sensible to write the *TS packets* as a side
 | ||||
|   // effect of reading, rather than the PES packets. Thus we also have
 | ||||
|   int               write_TS_packets; | ||||
|   // Obviously, one assumes that we are not going to be doing both at
 | ||||
|   // the same time (since they write through the same tswriter interface)
 | ||||
| 
 | ||||
|   // In either case, sometimes it is useful to suppress writing packets
 | ||||
|   // out for a while
 | ||||
|   int               suppress_writing; | ||||
| 
 | ||||
|   // Debugging: if this is set, and the appropriate code is compiled into
 | ||||
|   // pes.c (see DEBUG_READ_PACKETS), then report on each PES packet read
 | ||||
|   // and written. Even if DEBUG_READ_PACKETS is not defined, some output
 | ||||
|  |  | |||
							
								
								
									
										31
									
								
								pes_fns.h
								
								
								
								
							
							
						
						
									
										31
									
								
								pes_fns.h
								
								
								
								
							|  | @ -472,34 +472,43 @@ extern void report_PES_data_array2(int         stream_type, | |||
| // Server support
 | ||||
| // ============================================================
 | ||||
| /*
 | ||||
|  * Prepare for PES packets being written out to a TS writer, and | ||||
|  * request that they be written out. | ||||
|  * Packets can be written out to a client via a TS writer, as a | ||||
|  * "side effect" of reading them. The original mechanism was to | ||||
|  * write out PES packets (as TS) as they are read. This will work | ||||
|  * for PS or TS data, and writes out only those PES packets that | ||||
|  * have been read for video or audio data. | ||||
|  * | ||||
|  * The effect is that, each time a new PES packet is read in, it will | ||||
|  * be written out to the TS output stream. | ||||
|  * An alternative, which will only work for TS input data, is | ||||
|  * to write out TS packets as they are read. This will write all | ||||
|  * TS packets to the client. | ||||
|  * | ||||
|  * - `reader` is our PES reader context | ||||
|  * - `tswriter` is the TS writer | ||||
|  * - if `write_PES`, then write PES packets out as they are read from | ||||
|  *   the input, otherwise write TS packets. | ||||
|  * - `program_freq` is how often to write out program data (PAT/PMT) | ||||
|  *   if we are writing PES data (if we are writing TS data, then the | ||||
|  *   program data will be in the original TS packets) | ||||
|  */ | ||||
| extern void set_server_output(PES_reader_p  reader, | ||||
|                               TS_writer_p   tswriter, | ||||
|                               int           write_PES, | ||||
|                               int           program_freq); | ||||
| /*
 | ||||
|  * Start PES packets being written out to a TS writer (again). | ||||
|  * Start packets being written out to a TS writer (again). | ||||
|  * | ||||
|  * The effect is that, each time a new PES packet is read in, it will | ||||
|  * be written out to the TS output stream. | ||||
|  * If packets were already being written out, this does nothing. | ||||
|  * | ||||
|  * If PES packets were already being written out, this does nothing. | ||||
|  * If set_server_output() has not been called to define a TS writer | ||||
|  * context, this will have no effect. | ||||
|  * | ||||
|  * If `reader` is NULL, nothing is done. | ||||
|  */ | ||||
| extern void start_server_output(PES_reader_p  reader); | ||||
| /*
 | ||||
|  * Stop PES packets being written out to a TS writer. | ||||
|  * Stop packets being written out to a TS writer. | ||||
|  * | ||||
|  * If PES packets were already not being written out, this does nothing. | ||||
|  * If packets were already not being written out, this does nothing. | ||||
|  * | ||||
|  * If set_server_output() has not been called to define a TS writer | ||||
|  * context, this will have no effect. | ||||
|  | @ -517,6 +526,8 @@ extern void stop_server_output(PES_reader_p  reader); | |||
|  * the recipient, as the extra data (which has an irrelevant stream id) | ||||
|  * will be ignored by the video processor, but not by preceding systems. | ||||
|  * | ||||
|  * This does nothing if TS packets are being output directly. | ||||
|  * | ||||
|  * - `reader` is our PES reader context | ||||
|  * - `extra` is how many extra packets to output per "real" packet. | ||||
|  */ | ||||
|  |  | |||
							
								
								
									
										52
									
								
								tsserve.c
								
								
								
								
							
							
						
						
									
										52
									
								
								tsserve.c
								
								
								
								
							|  | @ -123,6 +123,9 @@ struct tsserve_context | |||
|   int      dolby_is_dvb; | ||||
|   int      force_stream_type; | ||||
|   int      repeat_program_every; | ||||
| 
 | ||||
|   // Transport Stream specific options
 | ||||
|   int      tsdirect; | ||||
| }; | ||||
| typedef struct tsserve_context *tsserve_context_p; | ||||
| 
 | ||||
|  | @ -2057,7 +2060,8 @@ static int play_pes_packets(PES_reader_p       reader[MAX_INPUT_FILES], | |||
|      | ||||
|     // Request that PES packets be written out to the TS writer as
 | ||||
|     // a "side effect" of reading them in
 | ||||
|     set_server_output(reader[ii],tswriter,context->repeat_program_every); | ||||
|     set_server_output(reader[ii],tswriter,!context->tsdirect, | ||||
|                       context->repeat_program_every); | ||||
|     set_server_padding(reader[ii],context->pes_padding); | ||||
|   } | ||||
|    | ||||
|  | @ -2115,6 +2119,18 @@ static int test_play(PES_reader_p    reader, | |||
|   int  started = FALSE; | ||||
|   int  ii; | ||||
| 
 | ||||
|   if (num_fast == 0 && num_faster == 0 && num_reverse == 0) | ||||
|   { | ||||
|     // Special case -- just play through
 | ||||
|     printf(">> Just playing at normal speed\n"); | ||||
|     set_PES_reader_video_only(reader,video_only); | ||||
|     err = play_normal(stream,tswriter,verbose,quiet,0,reverse_data); | ||||
|     if (err == EOF) | ||||
|       return 0; | ||||
|     else | ||||
|       return err; | ||||
|   } | ||||
| 
 | ||||
|   printf(">> Going through sequence twice\n"); | ||||
| 
 | ||||
|   for (ii=0; ii<2; ii++) | ||||
|  | @ -3080,7 +3096,8 @@ static int test_reader(tsserve_context_p  context, | |||
|   // Actually read the input and write the output...
 | ||||
|   // Request that PES packets be written out to the TS writer as
 | ||||
|   // a "side effect" of reading them in
 | ||||
|   set_server_output(reader,tswriter,context->repeat_program_every); | ||||
|   set_server_output(reader,tswriter,!context->tsdirect, | ||||
|                     context->repeat_program_every); | ||||
|   set_server_padding(reader,context->pes_padding); | ||||
| 
 | ||||
|   // And play...
 | ||||
|  | @ -3191,12 +3208,15 @@ static int command_reader(tsserve_context_p  context, | |||
|     return 1; | ||||
|   } | ||||
| 
 | ||||
|   // Request that PES packets be written out to the TS writer as
 | ||||
|   // a "side effect" of reading them in
 | ||||
|   // Request that packets be written out to the TS writer as a "side effect" of
 | ||||
|   // reading them in. The default is to write PES packets (just for the video
 | ||||
|   // and audio data), but the alternative is to write all TS packets (if the
 | ||||
|   // data *is* TS)
 | ||||
|   for (ii = 0; ii < MAX_INPUT_FILES; ii++) | ||||
|     if (reader[ii] != NULL) | ||||
|     { | ||||
|       set_server_output(reader[ii],tswriter,context->repeat_program_every); | ||||
|       set_server_output(reader[ii],tswriter,!context->tsdirect, | ||||
|                         context->repeat_program_every); | ||||
|       set_server_padding(reader[ii],context->pes_padding); | ||||
|     } | ||||
| 
 | ||||
|  | @ -3381,6 +3401,18 @@ static void print_detailed_usage() | |||
|     "  -dolby dvb       Use stream type 0x06 (the default)\n" | ||||
|     "  -dolby atsc      Use stream type 0x81\n" | ||||
|     "\n" | ||||
|     "Transport Stream Switches:\n" | ||||
|     "\n" | ||||
|     "  The following switches are only applicable if the input data is TS.\n" | ||||
|     "\n" | ||||
|     "  -tsdirect         In normal play, copy all TS packets to the client,\n" | ||||
|     "                    instead of just sending the PES packets for the video\n" | ||||
|     "                    and audio streams'\n" | ||||
|     "\n" | ||||
|     "  Note that when -tsdirect is specified, PES packets are still inspected\n" | ||||
|     "  to allow building up the fast forward/reverse indices.\n" | ||||
|     "  Also, -prepeat, -pes_padding and -drop will have no effect with this switch.\n" | ||||
|     "\n" | ||||
|     "Other stuff:\n" | ||||
|     "\n" | ||||
|     "  -prepeat <n>      Output the program data (PAT/PMT) after every <n>\n" | ||||
|  | @ -3452,6 +3484,9 @@ static void print_detailed_usage() | |||
|     "  -r <nr>           speed, then <nn> at normal speed again, then\n" | ||||
|     "                    reverse past <nr>. Repeat until stopped.\n" | ||||
|     "\n" | ||||
|     "  If '-f 0 -ff 0 -r 0' is specified, then the data will just play at\n" | ||||
|     "  normal speed, ignoring -n.\n" | ||||
|     "\n" | ||||
|     "  -skiptest         Test forwards and backwards skipping.\n" | ||||
|     "\n" | ||||
|     "  -output <name>, -o <name>\n" | ||||
|  | @ -3506,6 +3541,9 @@ int main(int argc, char **argv) | |||
|   context.pcr_pid    = context.video_pid; // Use PCRs from the video stream
 | ||||
|   context.repeat_program_every = 100; | ||||
| 
 | ||||
|   // Transport Stream specific options
 | ||||
|   context.tsdirect = FALSE;     // Write to server as a side effect of PES reading
 | ||||
| 
 | ||||
|   context.force_stream_type = FALSE; | ||||
|   context.want_h262 = TRUE; // shouldn't matter
 | ||||
|   context.dolby_is_dvb = TRUE; | ||||
|  | @ -3546,6 +3584,10 @@ int main(int argc, char **argv) | |||
|         action = ACTION_TEST; | ||||
|         skiptest = FALSE; | ||||
|       } | ||||
|       else if (!strcmp("-tsdirect",argv[argno])) | ||||
|       { | ||||
|         context.tsdirect = TRUE; // Write to server as a side effect of TS reading
 | ||||
|       } | ||||
|       else if (!strcmp("-n",argv[argno])) | ||||
|       { | ||||
|         CHECKARG("tsserve",argno); | ||||
|  |  | |||
		Ładowanie…
	
		Reference in New Issue
	
	 tibs
						tibs