kopia lustrzana https://github.com/F5OEO/tstools
770 wiersze
20 KiB
C
770 wiersze
20 KiB
C
/*
|
||
* Support for lists (actually arrays) of PID versus integer
|
||
*
|
||
* ***** BEGIN LICENSE BLOCK *****
|
||
* Version: MPL 1.1
|
||
*
|
||
* The contents of this file are subject to the Mozilla Public License Version
|
||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||
* the License. You may obtain a copy of the License at
|
||
* http://www.mozilla.org/MPL/
|
||
*
|
||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||
* for the specific language governing rights and limitations under the
|
||
* License.
|
||
*
|
||
* The Original Code is the MPEG TS, PS and ES tools.
|
||
*
|
||
* The Initial Developer of the Original Code is Amino Communications Ltd.
|
||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||
* the Initial Developer. All Rights Reserved.
|
||
*
|
||
* Contributor(s):
|
||
* Amino Communications Ltd, Swavesey, Cambridge UK
|
||
*
|
||
* ***** END LICENSE BLOCK *****
|
||
*/
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
|
||
#include "compat.h"
|
||
#include "pidint_fns.h"
|
||
#include "misc_fns.h"
|
||
#include "ts_fns.h"
|
||
#include "h222_defns.h"
|
||
|
||
// ============================================================================
|
||
// PIDINT LIST maintenance
|
||
// ============================================================================
|
||
/*
|
||
* Initialise a new pid/int list datastructure.
|
||
*/
|
||
extern int init_pidint_list(pidint_list_p list)
|
||
{
|
||
list->length = 0;
|
||
list->size = PIDINT_LIST_START_SIZE;
|
||
list->number = malloc(sizeof(int)*PIDINT_LIST_START_SIZE);
|
||
if (list->number == NULL)
|
||
{
|
||
fprintf(stderr,"### Unable to allocate array in program list datastructure\n");
|
||
return 1;
|
||
}
|
||
list->pid = malloc(sizeof(u_int32)*PIDINT_LIST_START_SIZE);
|
||
if (list->pid == NULL)
|
||
{
|
||
free(list->number);
|
||
fprintf(stderr,"### Unable to allocate array in program list datastructure\n");
|
||
return 1;
|
||
}
|
||
return 0;
|
||
|
||
}
|
||
|
||
/*
|
||
* Build a new pid/int list datastructure.
|
||
*
|
||
* Returns 0 if it succeeds, 1 if some error occurs.
|
||
*/
|
||
extern int build_pidint_list(pidint_list_p *list)
|
||
{
|
||
pidint_list_p new = malloc(SIZEOF_PIDINT_LIST);
|
||
if (new == NULL)
|
||
{
|
||
fprintf(stderr,"### Unable to allocate pid/int list datastructure\n");
|
||
return 1;
|
||
}
|
||
|
||
if (init_pidint_list(new))
|
||
return 1;
|
||
|
||
*list = new;
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* Add a pid/integer pair to the end of the list
|
||
*
|
||
* Returns 0 if it succeeds, 1 if some error occurs.
|
||
*/
|
||
extern int append_to_pidint_list(pidint_list_p list,
|
||
u_int32 pid,
|
||
int program)
|
||
{
|
||
if (list == NULL)
|
||
{
|
||
fprintf(stderr,"### Unable to append to NULL pid/int list\n");
|
||
return 1;
|
||
}
|
||
|
||
if (list->length == list->size)
|
||
{
|
||
int newsize = list->size + PIDINT_LIST_INCREMENT;
|
||
list->number = realloc(list->number,newsize*sizeof(int));
|
||
if (list->number == NULL)
|
||
{
|
||
fprintf(stderr,"### Unable to extend pid/int list array\n");
|
||
return 1;
|
||
}
|
||
list->pid = realloc(list->pid,newsize*sizeof(u_int32));
|
||
if (list->pid == NULL)
|
||
{
|
||
fprintf(stderr,"### Unable to extend pid/int list array\n");
|
||
return 1;
|
||
}
|
||
list->size = newsize;
|
||
}
|
||
list->number[list->length] = program;
|
||
list->pid[list->length] = pid;
|
||
list->length++;
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* Remove a pid/integer pair from the list
|
||
*
|
||
* Returns 0 if it succeeds, 1 if some error occurs.
|
||
*/
|
||
extern int remove_from_pidint_list(pidint_list_p list,
|
||
u_int32 pid)
|
||
{
|
||
int index;
|
||
int ii;
|
||
if (list == NULL)
|
||
{
|
||
fprintf(stderr,"### Unable to remove entry from NULL pid/int list\n");
|
||
return 1;
|
||
}
|
||
|
||
index = pid_index_in_pidint_list(list,pid);
|
||
if (index == -1)
|
||
{
|
||
fprintf(stderr,"### Cannot remove PID %04x from pid/int list"
|
||
" - it is not there\n",pid);
|
||
return 1;
|
||
}
|
||
|
||
for (ii = index; ii < (list->length - 1); ii++)
|
||
{
|
||
list->pid[ii] = list->pid[ii+1];
|
||
list->number[ii] = list->number[ii+1];
|
||
}
|
||
(list->length) --;
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* Tidy up and free a pid/int list datastructure after we've finished with it
|
||
*
|
||
* Clears the datastructure, frees it and returns `list` as NULL.
|
||
*
|
||
* Does nothing if `list` is already NULL.
|
||
*/
|
||
extern void free_pidint_list(pidint_list_p *list)
|
||
{
|
||
if (*list == NULL)
|
||
return;
|
||
if ((*list)->number != NULL)
|
||
{
|
||
free((*list)->number);
|
||
(*list)->number = NULL;
|
||
}
|
||
if ((*list)->pid != NULL)
|
||
{
|
||
free((*list)->pid);
|
||
(*list)->pid = NULL;
|
||
}
|
||
(*list)->length = 0;
|
||
(*list)->size = 0;
|
||
free(*list);
|
||
*list = NULL;
|
||
}
|
||
|
||
/*
|
||
* Report on a pid/int list's contents
|
||
*/
|
||
extern void report_pidint_list(pidint_list_p list,
|
||
char *list_name,
|
||
char *int_name,
|
||
int pid_first)
|
||
{
|
||
if (list == NULL)
|
||
printf("%s is NULL\n",list_name);
|
||
else if (list->length == 0)
|
||
printf("%s is empty\n",list_name);
|
||
else
|
||
{
|
||
int ii;
|
||
printf("%s:\n",list_name);
|
||
for (ii=0; ii<list->length; ii++)
|
||
{
|
||
if (pid_first)
|
||
printf(" PID %04x (%d) -> %s %d\n",
|
||
list->pid[ii],list->pid[ii],int_name,list->number[ii]);
|
||
else
|
||
printf(" %s %d -> PID %04x (%d)\n",
|
||
int_name,list->number[ii],list->pid[ii],list->pid[ii]);
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Lookup a PID to find its index in a pid/int list.
|
||
*
|
||
* Note that if `list` is NULL, then -1 will be returned - this is to
|
||
* allow the caller to make a query before they have read a list from the
|
||
* bitstream.
|
||
*
|
||
* Returns its index (0 or more) if the PID is in the list, -1 if it is not.
|
||
*/
|
||
extern int pid_index_in_pidint_list(pidint_list_p list,
|
||
u_int32 pid)
|
||
{
|
||
int ii;
|
||
if (list == NULL)
|
||
return -1;
|
||
for (ii = 0; ii < list->length; ii++)
|
||
{
|
||
if (list->pid[ii] == pid)
|
||
return ii;
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
/*
|
||
* Lookup a PID to find the corresponding integer value in a pid/int list.
|
||
*
|
||
* Returns 0 if the PID is in the list, -1 if it is not.
|
||
*/
|
||
extern int pid_int_in_pidint_list(pidint_list_p list,
|
||
u_int32 pid,
|
||
int *number)
|
||
{
|
||
int ii;
|
||
if (list == NULL)
|
||
return -1;
|
||
for (ii = 0; ii < list->length; ii++)
|
||
{
|
||
if (list->pid[ii] == pid)
|
||
{
|
||
*number = list->number[ii];
|
||
return 0;
|
||
}
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
/*
|
||
* Lookup a PID to see if it is in a pid/int list.
|
||
*
|
||
* Note that if `list` is NULL, then FALSE will be returned - this is to
|
||
* allow the caller to make a query before they have read a list from the
|
||
* bitstream.
|
||
*
|
||
* Returns TRUE if the PID is in the list, FALSE if it is not.
|
||
*/
|
||
extern int pid_in_pidint_list(pidint_list_p list,
|
||
u_int32 pid)
|
||
{
|
||
return pid_index_in_pidint_list(list,pid) != -1;
|
||
}
|
||
|
||
/*
|
||
* Check if two pid/int lists have the same content.
|
||
*
|
||
* Note that:
|
||
*
|
||
* - a list always compares as the same as itself
|
||
* - two NULL lists compare as the same
|
||
* - the *order* of PID/int pairs in the lists does not matter
|
||
*
|
||
* Returns TRUE if the two have the same content, FALSE otherwise.
|
||
*/
|
||
extern int same_pidint_list(pidint_list_p list1,
|
||
pidint_list_p list2)
|
||
{
|
||
int ii;
|
||
if (list1 == list2)
|
||
return TRUE;
|
||
else if (list1 == NULL || list2 == NULL)
|
||
return FALSE;
|
||
else if (list1->length != list2->length)
|
||
return FALSE;
|
||
for (ii = 0; ii < list1->length; ii++)
|
||
{
|
||
u_int32 pid = list1->pid[ii];
|
||
int idx = pid_index_in_pidint_list(list2,pid);
|
||
if (idx == -1)
|
||
return FALSE;
|
||
else if (list1->number[ii] != list2->number[idx])
|
||
return FALSE;
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
/*
|
||
* Report on a program stream list (a specialisation of report_pidint_list).
|
||
*
|
||
* - `list` is the stream list to report on
|
||
* - `prefix` is NULL or a string to put before each line printed
|
||
*/
|
||
extern void report_stream_list(pidint_list_p list,
|
||
char *prefix)
|
||
{
|
||
if (prefix!=NULL) printf(prefix);
|
||
if (list == NULL)
|
||
printf("Program stream list is NULL\n");
|
||
else if (list->length == 0)
|
||
printf("Program stream list is empty\n");
|
||
else
|
||
{
|
||
int ii;
|
||
printf("Program streams:\n");
|
||
for (ii=0; ii<list->length; ii++)
|
||
{
|
||
if (prefix!=NULL) printf(prefix);
|
||
printf(" PID %04x (%d) -> Stream type %3d (%s)\n",
|
||
list->pid[ii],list->pid[ii],list->number[ii],
|
||
H222_STREAM_TYPE_STR(list->number[ii]));
|
||
}
|
||
}
|
||
}
|
||
|
||
// ============================================================================
|
||
// PMT data maintenance
|
||
// ============================================================================
|
||
/*
|
||
* Initialise a PMT datastructure's stream lists
|
||
*/
|
||
static int init_pmt_streams(pmt_p pmt)
|
||
{
|
||
pmt->num_streams = 0;
|
||
pmt->streams_size = PMT_STREAMS_START_SIZE;
|
||
pmt->streams = malloc(SIZEOF_PMT_STREAM*PMT_STREAMS_START_SIZE);
|
||
if (pmt->streams == NULL)
|
||
{
|
||
fprintf(stderr,"### Unable to allocate streams in PMT datastructure\n");
|
||
return 1;
|
||
}
|
||
return 0;
|
||
|
||
}
|
||
|
||
/*
|
||
* Build a new PMT datastructure.
|
||
*
|
||
* `version_number` should be in the range 0-31, and will be treated as a
|
||
* number modulo 32 if it is not.
|
||
*
|
||
* `PCR_pid` should be a legitimate PCR PID - i.e., in the range 0x0010 to
|
||
* 0x1FFE, or 0x1FFF to indicate "unset". However, for convenience, the
|
||
* value 0 will also be accepted, and converted to 0x1FFF.
|
||
*
|
||
* Returns (a pointer to) the new PMT datastructure, or NULL if some error
|
||
* occurs.
|
||
*/
|
||
extern pmt_p build_pmt(u_int16 program_number, byte version_number,
|
||
u_int32 PCR_pid)
|
||
{
|
||
pmt_p new;
|
||
|
||
if (version_number > 31)
|
||
version_number = version_number % 32;
|
||
|
||
if (PCR_pid == 0)
|
||
PCR_pid = 0x1FFF; // unset
|
||
|
||
if (PCR_pid != 0x1FFF && (PCR_pid < 0x0010 || PCR_pid > 0x1ffe))
|
||
{
|
||
fprintf(stderr,"### Error building PMT datastructure\n"
|
||
" PCR PID %04x is outside legal program stream range\n",
|
||
PCR_pid);
|
||
return NULL;
|
||
}
|
||
|
||
new = malloc(SIZEOF_PMT);
|
||
if (new == NULL)
|
||
{
|
||
fprintf(stderr,"### Unable to allocate PMT datastructure\n");
|
||
return NULL;
|
||
}
|
||
|
||
new->program_number = program_number;
|
||
new->version_number = version_number;
|
||
new->PCR_pid = PCR_pid;
|
||
new->program_info_length = 0;
|
||
new->program_info = NULL;
|
||
|
||
if (init_pmt_streams(new))
|
||
{
|
||
free(new);
|
||
return NULL;
|
||
}
|
||
|
||
return new;
|
||
}
|
||
|
||
/*
|
||
* Set the descriptor data on a PMT. Specifically, 'program info',
|
||
* the descriptor data in the PMT "as a whole".
|
||
*
|
||
* Any previous program information for this PMT is lost.
|
||
*
|
||
* A copy of the program information bytes is taken.
|
||
*
|
||
* Returns 0 if it succeeds, 1 if some error occurs.
|
||
*/
|
||
extern int set_pmt_program_info(pmt_p pmt,
|
||
u_int16 program_info_length,
|
||
byte *program_info)
|
||
{
|
||
if (program_info_length > PMT_MAX_INFO_LENGTH)
|
||
{
|
||
fprintf(stderr,"### Program info length %d is more than %d\n",
|
||
program_info_length,PMT_MAX_INFO_LENGTH);
|
||
return 1;
|
||
}
|
||
if (pmt->program_info == NULL)
|
||
{
|
||
pmt->program_info = malloc(program_info_length);
|
||
if (pmt->program_info == NULL)
|
||
{
|
||
fprintf(stderr,"### Unable to allocate program info in PMT datastructure\n");
|
||
return 1;
|
||
}
|
||
}
|
||
else if (program_info_length != pmt->program_info_length)
|
||
{
|
||
// well, we might be shrinking it rather than growing it, but still
|
||
pmt->program_info = realloc(pmt->program_info,program_info_length);
|
||
if (pmt->program_info == NULL)
|
||
{
|
||
fprintf(stderr,"### Unable to extend program info in PMT datastructure\n");
|
||
return 1;
|
||
}
|
||
}
|
||
memcpy(pmt->program_info,program_info,program_info_length);
|
||
pmt->program_info_length = program_info_length;
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* Add a program stream to a PMT datastructure
|
||
*
|
||
* If `ES_info_length` is greater than 0, then `ES_info` is copied.
|
||
*
|
||
* Returns 0 if it succeeds, 1 if some error occurs.
|
||
*/
|
||
extern int add_stream_to_pmt(pmt_p pmt,
|
||
u_int32 elementary_PID,
|
||
byte stream_type,
|
||
u_int16 ES_info_length,
|
||
byte *ES_info)
|
||
{
|
||
if (pmt == NULL)
|
||
{
|
||
fprintf(stderr,"### Unable to append to NULL PMT datastructure\n");
|
||
return 1;
|
||
}
|
||
|
||
if (elementary_PID < 0x0010 || elementary_PID > 0x1ffe)
|
||
{
|
||
fprintf(stderr,"### Error adding stream to PMT\n"
|
||
" Elementary PID %04x is outside legal program stream range\n",
|
||
elementary_PID);
|
||
return 1;
|
||
}
|
||
|
||
if (ES_info_length > PMT_MAX_INFO_LENGTH)
|
||
{
|
||
fprintf(stderr,"### ES info length %d is more than %d\n",
|
||
ES_info_length,PMT_MAX_INFO_LENGTH);
|
||
return 1;
|
||
}
|
||
|
||
if (pmt->num_streams == pmt->streams_size)
|
||
{
|
||
int newsize = pmt->streams_size + PMT_STREAMS_INCREMENT;
|
||
pmt->streams = realloc(pmt->streams,newsize*SIZEOF_PMT_STREAM);
|
||
if (pmt->streams == NULL)
|
||
{
|
||
fprintf(stderr,"### Unable to extend PMT streams array\n");
|
||
return 1;
|
||
}
|
||
pmt->streams_size = newsize;
|
||
}
|
||
pmt->streams[pmt->num_streams].stream_type = stream_type;
|
||
pmt->streams[pmt->num_streams].elementary_PID = elementary_PID;
|
||
pmt->streams[pmt->num_streams].ES_info_length = ES_info_length;
|
||
if (ES_info_length > 0)
|
||
{
|
||
pmt->streams[pmt->num_streams].ES_info = malloc(ES_info_length);
|
||
if (pmt->streams[pmt->num_streams].ES_info == NULL)
|
||
{
|
||
fprintf(stderr,"### Unable to allocate PMT stream ES info\n");
|
||
return 1;
|
||
}
|
||
memcpy(pmt->streams[pmt->num_streams].ES_info,ES_info,ES_info_length);
|
||
}
|
||
else
|
||
pmt->streams[pmt->num_streams].ES_info = NULL;
|
||
pmt->num_streams++;
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* Free a PMT stream datastructure
|
||
*/
|
||
static void free_pmt_stream(pmt_stream_p stream)
|
||
{
|
||
if (stream == NULL) return;
|
||
if (stream->ES_info != NULL)
|
||
{
|
||
free(stream->ES_info);
|
||
stream->ES_info = NULL;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Remove a program stream from a PMT.
|
||
*
|
||
* Returns 0 if it succeeds, 1 if some error occurs.
|
||
*/
|
||
extern int remove_stream_from_pmt(pmt_p pmt,
|
||
u_int32 pid)
|
||
{
|
||
int index;
|
||
int ii;
|
||
if (pmt == NULL)
|
||
{
|
||
fprintf(stderr,"### Unable to remove entry from NULL PMT datastructure\n");
|
||
return 1;
|
||
}
|
||
|
||
index = pid_index_in_pmt(pmt,pid);
|
||
if (index == -1)
|
||
{
|
||
fprintf(stderr,"### Cannot remove PID %04x from PMT datastructure"
|
||
" - it is not there\n",pid);
|
||
return 1;
|
||
}
|
||
|
||
free_pmt_stream(&pmt->streams[index]);
|
||
|
||
for (ii = index; ii < (pmt->num_streams - 1); ii++)
|
||
pmt->streams[ii] = pmt->streams[ii+1];
|
||
(pmt->num_streams) --;
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* Tidy up and free a PMT datastructure after we've finished with it
|
||
*
|
||
* Clears the datastructure, frees it and returns `pmt` as NULL.
|
||
*
|
||
* Does nothing if `pmt` is already NULL.
|
||
*/
|
||
extern void free_pmt(pmt_p *pmt)
|
||
{
|
||
if (*pmt == NULL)
|
||
return;
|
||
if ((*pmt)->num_streams > 0)
|
||
{
|
||
int ii;
|
||
for (ii = 0; ii < (*pmt)->num_streams; ii++)
|
||
free_pmt_stream(&(*pmt)->streams[ii]);
|
||
(*pmt)->num_streams = 0;
|
||
}
|
||
if ((*pmt)->program_info != NULL)
|
||
{
|
||
free((*pmt)->program_info);
|
||
(*pmt)->program_info = NULL;
|
||
}
|
||
free((*pmt)->streams);
|
||
(*pmt)->program_info_length = 0;
|
||
free(*pmt);
|
||
*pmt = NULL;
|
||
}
|
||
|
||
/*
|
||
* Lookup a PID to find its index in a PMT datastructure.
|
||
*
|
||
* Note that if `pmt` is NULL, then -1 will be returned.
|
||
*
|
||
* Returns its index (0 or more) if the PID is in the list, -1 if it is not.
|
||
*/
|
||
extern int pid_index_in_pmt(pmt_p pmt,
|
||
u_int32 pid)
|
||
{
|
||
int ii;
|
||
if (pmt == NULL)
|
||
return -1;
|
||
for (ii = 0; ii < pmt->num_streams; ii++)
|
||
{
|
||
if (pmt->streams[ii].elementary_PID == pid)
|
||
return ii;
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
/*
|
||
* Lookup a PID to find the corresponding program stream information.
|
||
*
|
||
* Returns a pointer to the stream information if the PID is in the list,
|
||
* NULL if it is not.
|
||
*/
|
||
extern pmt_stream_p pid_stream_in_pmt(pmt_p pmt,
|
||
u_int32 pid)
|
||
{
|
||
int ii;
|
||
if (pmt == NULL)
|
||
return NULL;
|
||
for (ii = 0; ii < pmt->num_streams; ii++)
|
||
{
|
||
if (pmt->streams[ii].elementary_PID == pid)
|
||
return &pmt->streams[ii];
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
/*
|
||
* Lookup a PID to see if it is in a PMT datastructure.
|
||
*
|
||
* Note that if `pmt` is NULL, then FALSE will be returned.
|
||
*
|
||
* Returns TRUE if the PID is in the PMT's stream list, FALSE if it is not.
|
||
*/
|
||
extern int pid_in_pmt(pmt_p pmt,
|
||
u_int32 pid)
|
||
{
|
||
return pid_index_in_pmt(pmt,pid) != -1;
|
||
}
|
||
|
||
/*
|
||
* Check if two PMT streams have the same content.
|
||
*
|
||
* Returns TRUE if the two have the same content, FALSE otherwise.
|
||
*/
|
||
static int same_pmt_stream(pmt_stream_p str1,
|
||
pmt_stream_p str2)
|
||
{
|
||
if (str1 == str2) // !!!
|
||
return TRUE;
|
||
else if (str1 == NULL || str2 == NULL) // !!!
|
||
return FALSE;
|
||
else if (str1->elementary_PID != str2->elementary_PID)
|
||
return FALSE;
|
||
else if (str1->ES_info_length != str2->ES_info_length)
|
||
return FALSE;
|
||
else if (memcmp(str1->ES_info,str2->ES_info,str1->ES_info_length))
|
||
return FALSE;
|
||
else
|
||
return TRUE;
|
||
}
|
||
|
||
/*
|
||
* Check if two PMT datastructures have the same content.
|
||
*
|
||
* Note that:
|
||
*
|
||
* - a PMT datastructure always compares as the same as itself
|
||
* - two NULL datastructures compare as the same
|
||
* - a different version number means a different PMT
|
||
* - the *order* of program streams in the PMTs does not matter
|
||
* - descriptors must be identical as well, and byte order therein
|
||
* does matter (this may need changing later on)
|
||
*
|
||
* Returns TRUE if the two have the same content, FALSE otherwise.
|
||
*/
|
||
extern int same_pmt(pmt_p pmt1,
|
||
pmt_p pmt2)
|
||
{
|
||
int ii;
|
||
if (pmt1 == pmt2)
|
||
return TRUE;
|
||
else if (pmt1 == NULL || pmt2 == NULL)
|
||
return FALSE;
|
||
else if (pmt1->PCR_pid != pmt2->PCR_pid)
|
||
return FALSE;
|
||
else if (pmt1->version_number != pmt2->version_number)
|
||
return FALSE;
|
||
else if (pmt1->program_info_length != pmt2->program_info_length)
|
||
return FALSE;
|
||
else if (pmt1->num_streams != pmt2->num_streams)
|
||
return FALSE;
|
||
else if (memcmp(pmt1->program_info,pmt2->program_info,
|
||
pmt1->program_info_length))
|
||
return FALSE;
|
||
|
||
for (ii = 0; ii < pmt1->num_streams; ii++)
|
||
{
|
||
u_int32 pid = pmt1->streams[ii].elementary_PID;
|
||
int idx = pid_index_in_pmt(pmt2,pid);
|
||
if (idx == -1)
|
||
return FALSE;
|
||
else if (!same_pmt_stream(&pmt1->streams[ii],&pmt2->streams[idx]))
|
||
return FALSE;
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
/*
|
||
* Report on a PMT datastructure.
|
||
*
|
||
* - `stream` is the stream to write to
|
||
* - `prefix` is NULL or a string to put before each line printed
|
||
* - `pmt` is the PMT to report on
|
||
*/
|
||
extern void report_pmt(FILE *stream,
|
||
char *prefix,
|
||
pmt_p pmt)
|
||
{
|
||
if (prefix!=NULL) fprintf(stream,prefix);
|
||
if (pmt == NULL)
|
||
{
|
||
fprintf(stream,"PMT is NULL\n");
|
||
return;
|
||
}
|
||
else
|
||
fprintf(stream,"Program %d, version %d, PCR PID %04x (%d)\n",
|
||
pmt->program_number,pmt->version_number,pmt->PCR_pid,pmt->PCR_pid);
|
||
|
||
if (pmt->program_info_length > 0)
|
||
{
|
||
if (prefix!=NULL) fprintf(stream,prefix);
|
||
print_data(stream," Program info",pmt->program_info,
|
||
pmt->program_info_length,pmt->program_info_length);
|
||
print_descriptors(stream,prefix," ",pmt->program_info,
|
||
pmt->program_info_length);
|
||
}
|
||
if (pmt->num_streams > 0)
|
||
{
|
||
int ii;
|
||
if (prefix!=NULL) fprintf(stream,prefix);
|
||
fprintf(stream,"Program streams:\n");
|
||
for (ii=0; ii<pmt->num_streams; ii++)
|
||
{
|
||
if (prefix!=NULL) fprintf(stream,prefix);
|
||
fprintf(stream," PID %04x (%4d) -> Stream type %02x (%3d) %s\n",
|
||
pmt->streams[ii].elementary_PID,
|
||
pmt->streams[ii].elementary_PID,
|
||
pmt->streams[ii].stream_type,
|
||
pmt->streams[ii].stream_type,
|
||
H222_STREAM_TYPE_STR(pmt->streams[ii].stream_type));
|
||
if (pmt->streams[ii].ES_info_length > 0)
|
||
{
|
||
if (prefix!=NULL) fprintf(stream,prefix);
|
||
print_data(stream," ES info",
|
||
pmt->streams[ii].ES_info,
|
||
pmt->streams[ii].ES_info_length,
|
||
pmt->streams[ii].ES_info_length);
|
||
print_descriptors(stream,prefix," ",
|
||
pmt->streams[ii].ES_info,
|
||
pmt->streams[ii].ES_info_length);
|
||
}
|
||
}
|
||
}
|
||
}
|