// ITU-T H.222.0(10/2014) // Information technology – Generic coding of moving pictures and associated audio information: Systems // 2.4.3.6 PES packet(p51) #include "mpeg-pes-proto.h" #include #include /// @return 0-error, other-pes header length size_t pes_read_header(struct pes_t *pes, const uint8_t *data, size_t bytes) { size_t i; assert(0x00 == data[0] && 0x00 == data[1] && 0x01 == data[2]); pes->sid = data[3]; pes->len = (data[4] << 8) | data[5]; i = 6; assert(0x02 == ((data[i] >> 6) & 0x3)); pes->PES_scrambling_control = (data[i] >> 4) & 0x3; pes->PES_priority = (data[i] >> 3) & 0x1; pes->data_alignment_indicator = (data[i] >> 2) & 0x1; pes->copyright = (data[i] >> 1) & 0x1; pes->original_or_copy = data[i] & 0x1; i++; pes->PTS_DTS_flags = (data[i] >> 6) & 0x3; pes->ESCR_flag = (data[i] >> 5) & 0x1; pes->ES_rate_flag = (data[i] >> 4) & 0x1; pes->DSM_trick_mode_flag = (data[i] >> 3) & 0x1; pes->additional_copy_info_flag = (data[i] >> 2) & 0x1; pes->PES_CRC_flag = (data[i] >> 1) & 0x1; pes->PES_extension_flag = data[i] & 0x1; i++; pes->PES_header_data_length = data[i]; if (bytes < pes->PES_header_data_length + 9) { return 0; // invalid data length } i++; if (0x02 & pes->PTS_DTS_flags) { assert(0x20 == (data[i] & 0x20)); pes->pts = ((((uint64_t)data[i] >> 1) & 0x07) << 30) | ((uint64_t)data[i + 1] << 22) | ((((uint64_t)data[i + 2] >> 1) & 0x7F) << 15) | ((uint64_t)data[i + 3] << 7) | ((data[i + 4] >> 1) & 0x7F); i += 5; } //else //{ // pes->pts = PTS_NO_VALUE; //} if (0x01 & pes->PTS_DTS_flags) { assert(0x10 == (data[i] & 0x10)); pes->dts = ((((uint64_t)data[i] >> 1) & 0x07) << 30) | ((uint64_t)data[i + 1] << 22) | ((((uint64_t)data[i + 2] >> 1) & 0x7F) << 15) | ((uint64_t)data[i + 3] << 7) | ((data[i + 4] >> 1) & 0x7F); i += 5; } else if (0x02 & pes->PTS_DTS_flags) { // has pts pes->dts = pes->pts; } //else //{ // pes->dts = PTS_NO_VALUE; //} if (pes->ESCR_flag) { pes->ESCR_base = ((((uint64_t)data[i] >> 3) & 0x07) << 30) | (((uint64_t)data[i] & 0x03) << 28) | ((uint64_t)data[i + 1] << 20) | ((((uint64_t)data[i + 2] >> 3) & 0x1F) << 15) | (((uint64_t)data[i + 2] & 0x3) << 13) | ((uint64_t)data[i + 3] << 5) | ((data[i + 4] >> 3) & 0x1F); pes->ESCR_extension = ((data[i + 4] & 0x03) << 7) | ((data[i + 5] >> 1) & 0x7F); i += 6; } if (pes->ES_rate_flag) { pes->ES_rate = ((data[i] & 0x7F) << 15) | (data[i + 1] << 7) | ((data[i + 2] >> 1) & 0x7F); i += 3; } if (pes->DSM_trick_mode_flag) { // TODO: i += 1; } if (pes->additional_copy_info_flag) { i += 1; } if (pes->PES_CRC_flag) { i += 2; } if (pes->PES_extension_flag) { } if (pes->len > 0) { pes->len -= pes->PES_header_data_length + 3; } return pes->PES_header_data_length + 9; } /// @return 0-error, pes header length size_t pes_write_header(const struct pes_t *pes, uint8_t *data, size_t bytes) { uint8_t len = 0; uint8_t flags = 0x00; uint8_t *p = NULL; if (bytes < 9) { return 0; // error } // packet_start_code_prefix 0x000001 data[0] = 0x00; data[1] = 0x00; data[2] = 0x01; data[3] = pes->sid; // skip PES_packet_length //data[4] = 0x00; //data[5] = 0x00; // '10' // PES_scrambling_control '00' // PES_priority '0' // data_alignment_indicator '1' // copyright '0' // original_or_copy '0' data[6] = 0x80; if (pes->data_alignment_indicator) { data[6] |= 0x04; } //if (IDR | subtitle | raw data) //data[6] |= 0x04; // PTS_DTS_flag 'xx' // ESCR_flag '0' // ES_rate_flag '0' // DSM_trick_mode_flag '0' // additional_copy_info_flag '0' // PES_CRC_flag '0' // PES_extension_flag '0' if (PTS_NO_VALUE != pes->pts) { flags |= 0x80; // pts len += 5; } assert(PTS_NO_VALUE == pes->dts || pes->pts == pes->dts || PES_SID_VIDEO == data[3]); // audio PTS==DTS if (PTS_NO_VALUE != pes->dts /*&& PES_SID_VIDEO==(PES_SID_VIDEO&data[3])*/ && pes->dts != pes->pts) { flags |= 0x40; // dts len += 5; } data[7] = flags; // PES_header_data_length : 8 data[8] = len; if ((size_t)len + 9 > bytes) { return 0; // error } p = data + 9; if (flags & 0x80) { *p++ = ((flags >> 2) & 0x30)/* 0011/0010 */ | (((pes->pts >> 30) & 0x07) << 1) /* PTS 30-32 */ | 0x01 /* marker_bit */; *p++ = (pes->pts >> 22) & 0xFF; /* PTS 22-29 */ *p++ = ((pes->pts >> 14) & 0xFE) /* PTS 15-21 */ | 0x01 /* marker_bit */; *p++ = (pes->pts >> 7) & 0xFF; /* PTS 7-14 */ *p++ = ((pes->pts << 1) & 0xFE) /* PTS 0-6 */ | 0x01 /* marker_bit */; } if (flags & 0x40) { *p++ = 0x10 /* 0001 */ | (((pes->dts >> 30) & 0x07) << 1) /* DTS 30-32 */ | 0x01 /* marker_bit */; *p++ = (pes->dts >> 22) & 0xFF; /* DTS 22-29 */ *p++ = ((pes->dts >> 14) & 0xFE) /* DTS 15-21 */ | 0x01 /* marker_bit */; *p++ = (pes->dts >> 7) & 0xFF; /* DTS 7-14 */ *p++ = ((pes->dts << 1) & 0xFE) /* DTS 0-6 */ | 0x01 /* marker_bit */; } return p - data; } size_t pes_read_mpeg1_header(struct pes_t *pes, const uint8_t *data, size_t bytes) { size_t i; assert(0x00 == data[0] && 0x00 == data[1] && 0x01 == data[2]); pes->sid = data[3]; pes->len = (data[4] << 8) | data[5]; for (i = 6; data[i] == 0xFF && i < bytes;) { i++; } if (0x40 == (0xC0 & data[i])) { i += 2; // skip STD_buffer_scale / STD_buffer_size } if (0x20 == (0xF0 & data[i])) { pes->pts = ((((uint64_t)data[i] >> 1) & 0x07) << 30) | ((uint64_t)data[i + 1] << 22) | ((((uint64_t)data[i + 2] >> 1) & 0x7F) << 15) | ((uint64_t)data[i + 3] << 7) | ((data[i + 4] >> 1) & 0x7F); i += 5; } else if (0x30 == (0xF0 & data[i])) { pes->pts = ((((uint64_t)data[i] >> 1) & 0x07) << 30) | ((uint64_t)data[i + 1] << 22) | ((((uint64_t)data[i + 2] >> 1) & 0x7F) << 15) | ((uint64_t)data[i + 3] << 7) | ((data[i + 4] >> 1) & 0x7F); pes->dts = ((((uint64_t)data[i + 5] >> 1) & 0x07) << 30) | ((uint64_t)data[i + 6] << 22) | ((((uint64_t)data[i + 7] >> 1) & 0x7F) << 15) | ((uint64_t)data[i + 8] << 7) | ((data[i + 9] >> 1) & 0x7F); i += 10; } else { assert(0x0F == data[i]); i += 1; } pes->len -= i - 6; return i; }