[Bug?] Invalid transport_descriptors_length field calculation in NIT generator

Michael Umansky <[email protected]> Wed, 10 Sep 2014 11:33:45 +0300
Newsgroups gmane.comp.video.videolan.libdvbpsi.devel
Message-ID <[email protected]>
Hello,

The calculation of the transport_descriptors_length field in NIT has one 
extra byte than it should.

I am attaching the test file used to create an NIT containing one 
program. Using libdvbpsi-1.2.0.

Here is the hex dump of the output file, I have bolded the invalid byte.

% hd out.ts
00000000  47 40 10 10 00 40 b0 13  05 39 c3 00 00 f0 00 f0  
|G@[email protected]......|
00000010  06 02 9a 05 39 f0 *01*5f  b2 83 b6 ff ff ff ff ff  
|....9.._........|
00000020  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  
|................|
*
000000bc

It should be 0x00 as there are no descriptors attached. EN 300 468 
V1.13.1 explicitly states:
transport_descriptors_length: This is a 12-bit field specifying the 
total length in bytes of the TS descriptors /that follow/. (emphasis mine)

Curiously enough, if you create a dummy NIT containing no programs, the 
highlighted byte is correctly set to 0x00.

For your consideration.

Thanks,
Michael

_______________________________________________
libdvbpsi-devel mailing list
[email protected]
https://mailman.videolan.org/listinfo/libdvbpsi-devel
test.c (text/x-csrc, 2.6 KB)
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>

#include "path/to/libdvbpsi/config.h"

#include <dvbpsi/dvbpsi.h>
#include <dvbpsi/psi.h>
#include <dvbpsi/descriptor.h>
#include <dvbpsi/nit.h>

static void message(dvbpsi_t *handle, const dvbpsi_msg_level_t level, const char *msg) {

    switch(level) {
        case DVBPSI_MSG_ERROR:
            fprintf(stderr, "%s", msg);
            break;
        case DVBPSI_MSG_WARN:
            fprintf(stderr, "%s", msg);
            break;
        case DVBPSI_MSG_DEBUG:
            fprintf(stdout, "%s", msg);
            break;
        default:
            return;
    }
}

static void write_psi(dvbpsi_psi_section_t *section, const uint16_t pid, uint8_t *packet, FILE *fp) {

    packet[0] = 0x47;

    while (section) {
        size_t bytes_written = 0;
        uint8_t *position_in_ts;
        uint8_t *byte = section->p_data;
        uint8_t *end  = section->p_payload_end + (section->b_syntax_indicator ? 4 : 0);

        packet[1] |= 0x40 | (pid >> 8);
        packet[2] = pid & 0xFF;
        packet[3] = (packet[3] & 0x0F) | 0x10;

        packet[4] = 0x00;
        position_in_ts = packet + 5;

        while (position_in_ts < packet + 188 && byte < end)
            *(position_in_ts++) = *(byte++);
        while (position_in_ts < packet + 188)
            *(position_in_ts++) = 0xFF;

        bytes_written = fwrite(packet, 188, 1, fp);
        if (bytes_written == 0)
            return;

        packet[3] = (packet[3] + 1) & 0x0F;

        while (byte < end) {
            packet[1] &= 0xBF;
            packet[3] = (packet[3] & 0x0F) | 0x10;

            position_in_ts = packet + 4;

            while (position_in_ts < packet + 188 && byte < end)
                *(position_in_ts++) = *(byte++);
            while (position_in_ts < packet + 188)
                *(position_in_ts++) = 0xFF;
            bytes_written = fwrite(packet, 188, 1, fp);
            if (bytes_written == 0)
                return;

            packet[3] = (packet[3] + 1) & 0x0F;
        }

        section = section->p_next;
    }
}

int main(void) {

    FILE *fp;
    uint8_t packet[188] = { 0 };

    dvbpsi_t *dvbpsi = dvbpsi_new(&message, DVBPSI_MSG_DEBUG);
    dvbpsi_nit_t *nit = dvbpsi_nit_new(0x40, 666, 1337, 1, true);
    dvbpsi_psi_section_t *sections = NULL;

    dvbpsi_nit_ts_add(nit, 666, 1337);

    fp = fopen("out.ts", "wb");
    if (fp == NULL)
        goto out;

    sections = dvbpsi_nit_sections_generate(dvbpsi, nit, 0x40);
    write_psi(sections, 0x10, packet, fp);
    fclose(fp);

out:
    dvbpsi_nit_delete(nit);
    dvbpsi_DeletePSISections(sections);
    dvbpsi_delete(dvbpsi);

    return 0;
}