162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Vidtv serves as a reference DVB driver and helps validate the existing APIs 462306a36Sopenharmony_ci * in the media subsystem. It can also aid developers working on userspace 562306a36Sopenharmony_ci * applications. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * This file contains the logic to translate the ES data for one access unit 862306a36Sopenharmony_ci * from an encoder into MPEG TS packets. It does so by first encapsulating it 962306a36Sopenharmony_ci * with a PES header and then splitting it into TS packets. 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Copyright (C) 2020 Daniel W. S. Almeida 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ":%s, %d: " fmt, __func__, __LINE__ 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <linux/types.h> 1762306a36Sopenharmony_ci#include <linux/printk.h> 1862306a36Sopenharmony_ci#include <linux/ratelimit.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "vidtv_pes.h" 2162306a36Sopenharmony_ci#include "vidtv_common.h" 2262306a36Sopenharmony_ci#include "vidtv_encoder.h" 2362306a36Sopenharmony_ci#include "vidtv_ts.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define PRIVATE_STREAM_1_ID 0xbd /* private_stream_1. See SMPTE 302M-2007 p.6 */ 2662306a36Sopenharmony_ci#define PES_HEADER_MAX_STUFFING_BYTES 32 2762306a36Sopenharmony_ci#define PES_TS_HEADER_MAX_STUFFING_BYTES 182 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic u32 vidtv_pes_op_get_len(bool send_pts, bool send_dts) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci u32 len = 0; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci /* the flags must always be sent */ 3462306a36Sopenharmony_ci len += sizeof(struct vidtv_pes_optional); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci /* From all optionals, we might send these for now */ 3762306a36Sopenharmony_ci if (send_pts && send_dts) 3862306a36Sopenharmony_ci len += sizeof(struct vidtv_pes_optional_pts_dts); 3962306a36Sopenharmony_ci else if (send_pts) 4062306a36Sopenharmony_ci len += sizeof(struct vidtv_pes_optional_pts); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci return len; 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#define SIZE_PCR (6 + sizeof(struct vidtv_mpeg_ts_adaption)) 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic u32 vidtv_pes_h_get_len(bool send_pts, bool send_dts) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci u32 len = 0; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci /* PES header length notwithstanding stuffing bytes */ 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci len += sizeof(struct vidtv_mpeg_pes); 5462306a36Sopenharmony_ci len += vidtv_pes_op_get_len(send_pts, send_dts); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci return len; 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic u32 vidtv_pes_write_header_stuffing(struct pes_header_write_args *args) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci /* 6262306a36Sopenharmony_ci * This is a fixed 8-bit value equal to '0xFF' that can be inserted 6362306a36Sopenharmony_ci * by the encoder, for example to meet the requirements of the channel. 6462306a36Sopenharmony_ci * It is discarded by the decoder. No more than 32 stuffing bytes shall 6562306a36Sopenharmony_ci * be present in one PES packet header. 6662306a36Sopenharmony_ci */ 6762306a36Sopenharmony_ci if (args->n_pes_h_s_bytes > PES_HEADER_MAX_STUFFING_BYTES) { 6862306a36Sopenharmony_ci pr_warn_ratelimited("More than %d stuffing bytes in PES packet header\n", 6962306a36Sopenharmony_ci PES_HEADER_MAX_STUFFING_BYTES); 7062306a36Sopenharmony_ci args->n_pes_h_s_bytes = PES_HEADER_MAX_STUFFING_BYTES; 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci return vidtv_memset(args->dest_buf, 7462306a36Sopenharmony_ci args->dest_offset, 7562306a36Sopenharmony_ci args->dest_buf_sz, 7662306a36Sopenharmony_ci TS_FILL_BYTE, 7762306a36Sopenharmony_ci args->n_pes_h_s_bytes); 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic u32 vidtv_pes_write_pts_dts(struct pes_header_write_args *args) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci u32 nbytes = 0; /* the number of bytes written by this function */ 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci struct vidtv_pes_optional_pts pts = {}; 8562306a36Sopenharmony_ci struct vidtv_pes_optional_pts_dts pts_dts = {}; 8662306a36Sopenharmony_ci void *op = NULL; 8762306a36Sopenharmony_ci size_t op_sz = 0; 8862306a36Sopenharmony_ci u64 mask1; 8962306a36Sopenharmony_ci u64 mask2; 9062306a36Sopenharmony_ci u64 mask3; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (!args->send_pts && args->send_dts) 9362306a36Sopenharmony_ci return 0; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci mask1 = GENMASK_ULL(32, 30); 9662306a36Sopenharmony_ci mask2 = GENMASK_ULL(29, 15); 9762306a36Sopenharmony_ci mask3 = GENMASK_ULL(14, 0); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci /* see ISO/IEC 13818-1 : 2000 p. 32 */ 10062306a36Sopenharmony_ci if (args->send_pts && args->send_dts) { 10162306a36Sopenharmony_ci pts_dts.pts1 = (0x3 << 4) | ((args->pts & mask1) >> 29) | 0x1; 10262306a36Sopenharmony_ci pts_dts.pts2 = cpu_to_be16(((args->pts & mask2) >> 14) | 0x1); 10362306a36Sopenharmony_ci pts_dts.pts3 = cpu_to_be16(((args->pts & mask3) << 1) | 0x1); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci pts_dts.dts1 = (0x1 << 4) | ((args->dts & mask1) >> 29) | 0x1; 10662306a36Sopenharmony_ci pts_dts.dts2 = cpu_to_be16(((args->dts & mask2) >> 14) | 0x1); 10762306a36Sopenharmony_ci pts_dts.dts3 = cpu_to_be16(((args->dts & mask3) << 1) | 0x1); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci op = &pts_dts; 11062306a36Sopenharmony_ci op_sz = sizeof(pts_dts); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci } else if (args->send_pts) { 11362306a36Sopenharmony_ci pts.pts1 = (0x1 << 5) | ((args->pts & mask1) >> 29) | 0x1; 11462306a36Sopenharmony_ci pts.pts2 = cpu_to_be16(((args->pts & mask2) >> 14) | 0x1); 11562306a36Sopenharmony_ci pts.pts3 = cpu_to_be16(((args->pts & mask3) << 1) | 0x1); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci op = &pts; 11862306a36Sopenharmony_ci op_sz = sizeof(pts); 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci /* copy PTS/DTS optional */ 12262306a36Sopenharmony_ci nbytes += vidtv_memcpy(args->dest_buf, 12362306a36Sopenharmony_ci args->dest_offset + nbytes, 12462306a36Sopenharmony_ci args->dest_buf_sz, 12562306a36Sopenharmony_ci op, 12662306a36Sopenharmony_ci op_sz); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci return nbytes; 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic u32 vidtv_pes_write_h(struct pes_header_write_args *args) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci u32 nbytes = 0; /* the number of bytes written by this function */ 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci struct vidtv_mpeg_pes pes_header = {}; 13662306a36Sopenharmony_ci struct vidtv_pes_optional pes_optional = {}; 13762306a36Sopenharmony_ci struct pes_header_write_args pts_dts_args; 13862306a36Sopenharmony_ci u32 stream_id = (args->encoder_id == S302M) ? PRIVATE_STREAM_1_ID : args->stream_id; 13962306a36Sopenharmony_ci u16 pes_opt_bitfield = 0x01 << 15; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci pes_header.bitfield = cpu_to_be32((PES_START_CODE_PREFIX << 8) | stream_id); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci pes_header.length = cpu_to_be16(vidtv_pes_op_get_len(args->send_pts, 14462306a36Sopenharmony_ci args->send_dts) + 14562306a36Sopenharmony_ci args->access_unit_len); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci if (args->send_pts && args->send_dts) 14862306a36Sopenharmony_ci pes_opt_bitfield |= (0x3 << 6); 14962306a36Sopenharmony_ci else if (args->send_pts) 15062306a36Sopenharmony_ci pes_opt_bitfield |= (0x1 << 7); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci pes_optional.bitfield = cpu_to_be16(pes_opt_bitfield); 15362306a36Sopenharmony_ci pes_optional.length = vidtv_pes_op_get_len(args->send_pts, args->send_dts) + 15462306a36Sopenharmony_ci args->n_pes_h_s_bytes - 15562306a36Sopenharmony_ci sizeof(struct vidtv_pes_optional); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci /* copy header */ 15862306a36Sopenharmony_ci nbytes += vidtv_memcpy(args->dest_buf, 15962306a36Sopenharmony_ci args->dest_offset + nbytes, 16062306a36Sopenharmony_ci args->dest_buf_sz, 16162306a36Sopenharmony_ci &pes_header, 16262306a36Sopenharmony_ci sizeof(pes_header)); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* copy optional header bits */ 16562306a36Sopenharmony_ci nbytes += vidtv_memcpy(args->dest_buf, 16662306a36Sopenharmony_ci args->dest_offset + nbytes, 16762306a36Sopenharmony_ci args->dest_buf_sz, 16862306a36Sopenharmony_ci &pes_optional, 16962306a36Sopenharmony_ci sizeof(pes_optional)); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci /* copy the timing information */ 17262306a36Sopenharmony_ci pts_dts_args = *args; 17362306a36Sopenharmony_ci pts_dts_args.dest_offset = args->dest_offset + nbytes; 17462306a36Sopenharmony_ci nbytes += vidtv_pes_write_pts_dts(&pts_dts_args); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci /* write any PES header stuffing */ 17762306a36Sopenharmony_ci nbytes += vidtv_pes_write_header_stuffing(args); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci return nbytes; 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic u32 vidtv_pes_write_pcr_bits(u8 *to, u32 to_offset, u64 pcr) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci /* Exact same from ffmpeg. PCR is a counter driven by a 27Mhz clock */ 18562306a36Sopenharmony_ci u64 div; 18662306a36Sopenharmony_ci u64 rem; 18762306a36Sopenharmony_ci u8 *buf = to + to_offset; 18862306a36Sopenharmony_ci u64 pcr_low; 18962306a36Sopenharmony_ci u64 pcr_high; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci div = div64_u64_rem(pcr, 300, &rem); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci pcr_low = rem; /* pcr_low = pcr % 300 */ 19462306a36Sopenharmony_ci pcr_high = div; /* pcr_high = pcr / 300 */ 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci *buf++ = pcr_high >> 25; 19762306a36Sopenharmony_ci *buf++ = pcr_high >> 17; 19862306a36Sopenharmony_ci *buf++ = pcr_high >> 9; 19962306a36Sopenharmony_ci *buf++ = pcr_high >> 1; 20062306a36Sopenharmony_ci *buf++ = pcr_high << 7 | pcr_low >> 8 | 0x7e; 20162306a36Sopenharmony_ci *buf++ = pcr_low; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci return 6; 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic u32 vidtv_pes_write_stuffing(struct pes_ts_header_write_args *args, 20762306a36Sopenharmony_ci u32 dest_offset, bool need_pcr, 20862306a36Sopenharmony_ci u64 *last_pcr) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci struct vidtv_mpeg_ts_adaption ts_adap = {}; 21162306a36Sopenharmony_ci int stuff_nbytes; 21262306a36Sopenharmony_ci u32 nbytes = 0; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (!args->n_stuffing_bytes) 21562306a36Sopenharmony_ci return 0; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci ts_adap.random_access = 1; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci /* length _immediately_ following 'adaptation_field_length' */ 22062306a36Sopenharmony_ci if (need_pcr) { 22162306a36Sopenharmony_ci ts_adap.PCR = 1; 22262306a36Sopenharmony_ci ts_adap.length = SIZE_PCR; 22362306a36Sopenharmony_ci } else { 22462306a36Sopenharmony_ci ts_adap.length = sizeof(ts_adap); 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci stuff_nbytes = args->n_stuffing_bytes - ts_adap.length; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci ts_adap.length -= sizeof(ts_adap.length); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci if (unlikely(stuff_nbytes < 0)) 23162306a36Sopenharmony_ci stuff_nbytes = 0; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci ts_adap.length += stuff_nbytes; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci /* write the adap after the TS header */ 23662306a36Sopenharmony_ci nbytes += vidtv_memcpy(args->dest_buf, 23762306a36Sopenharmony_ci dest_offset + nbytes, 23862306a36Sopenharmony_ci args->dest_buf_sz, 23962306a36Sopenharmony_ci &ts_adap, 24062306a36Sopenharmony_ci sizeof(ts_adap)); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci /* write the optional PCR */ 24362306a36Sopenharmony_ci if (need_pcr) { 24462306a36Sopenharmony_ci nbytes += vidtv_pes_write_pcr_bits(args->dest_buf, 24562306a36Sopenharmony_ci dest_offset + nbytes, 24662306a36Sopenharmony_ci args->pcr); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci *last_pcr = args->pcr; 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci /* write the stuffing bytes, if are there anything left */ 25262306a36Sopenharmony_ci if (stuff_nbytes) 25362306a36Sopenharmony_ci nbytes += vidtv_memset(args->dest_buf, 25462306a36Sopenharmony_ci dest_offset + nbytes, 25562306a36Sopenharmony_ci args->dest_buf_sz, 25662306a36Sopenharmony_ci TS_FILL_BYTE, 25762306a36Sopenharmony_ci stuff_nbytes); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci /* 26062306a36Sopenharmony_ci * The n_stuffing_bytes contain a pre-calculated value of 26162306a36Sopenharmony_ci * the amount of data that this function would read, made from 26262306a36Sopenharmony_ci * vidtv_pes_h_get_len(). If something went wrong, print a warning 26362306a36Sopenharmony_ci */ 26462306a36Sopenharmony_ci if (nbytes != args->n_stuffing_bytes) 26562306a36Sopenharmony_ci pr_warn_ratelimited("write size was %d, expected %d\n", 26662306a36Sopenharmony_ci nbytes, args->n_stuffing_bytes); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci return nbytes; 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic u32 vidtv_pes_write_ts_h(struct pes_ts_header_write_args args, 27262306a36Sopenharmony_ci bool need_pcr, u64 *last_pcr) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci /* number of bytes written by this function */ 27562306a36Sopenharmony_ci u32 nbytes = 0; 27662306a36Sopenharmony_ci struct vidtv_mpeg_ts ts_header = {}; 27762306a36Sopenharmony_ci u16 payload_start = !args.wrote_pes_header; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci ts_header.sync_byte = TS_SYNC_BYTE; 28062306a36Sopenharmony_ci ts_header.bitfield = cpu_to_be16((payload_start << 14) | args.pid); 28162306a36Sopenharmony_ci ts_header.scrambling = 0; 28262306a36Sopenharmony_ci ts_header.adaptation_field = (args.n_stuffing_bytes) > 0; 28362306a36Sopenharmony_ci ts_header.payload = (args.n_stuffing_bytes) < PES_TS_HEADER_MAX_STUFFING_BYTES; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci ts_header.continuity_counter = *args.continuity_counter; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci vidtv_ts_inc_cc(args.continuity_counter); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci /* write the TS header */ 29062306a36Sopenharmony_ci nbytes += vidtv_memcpy(args.dest_buf, 29162306a36Sopenharmony_ci args.dest_offset + nbytes, 29262306a36Sopenharmony_ci args.dest_buf_sz, 29362306a36Sopenharmony_ci &ts_header, 29462306a36Sopenharmony_ci sizeof(ts_header)); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci /* write stuffing, if any */ 29762306a36Sopenharmony_ci nbytes += vidtv_pes_write_stuffing(&args, args.dest_offset + nbytes, 29862306a36Sopenharmony_ci need_pcr, last_pcr); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci return nbytes; 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ciu32 vidtv_pes_write_into(struct pes_write_args *args) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci u32 unaligned_bytes = (args->dest_offset % TS_PACKET_LEN); 30662306a36Sopenharmony_ci struct pes_ts_header_write_args ts_header_args = { 30762306a36Sopenharmony_ci .dest_buf = args->dest_buf, 30862306a36Sopenharmony_ci .dest_buf_sz = args->dest_buf_sz, 30962306a36Sopenharmony_ci .pid = args->pid, 31062306a36Sopenharmony_ci .pcr = args->pcr, 31162306a36Sopenharmony_ci .continuity_counter = args->continuity_counter, 31262306a36Sopenharmony_ci }; 31362306a36Sopenharmony_ci struct pes_header_write_args pes_header_args = { 31462306a36Sopenharmony_ci .dest_buf = args->dest_buf, 31562306a36Sopenharmony_ci .dest_buf_sz = args->dest_buf_sz, 31662306a36Sopenharmony_ci .encoder_id = args->encoder_id, 31762306a36Sopenharmony_ci .send_pts = args->send_pts, 31862306a36Sopenharmony_ci .pts = args->pts, 31962306a36Sopenharmony_ci .send_dts = args->send_dts, 32062306a36Sopenharmony_ci .dts = args->dts, 32162306a36Sopenharmony_ci .stream_id = args->stream_id, 32262306a36Sopenharmony_ci .n_pes_h_s_bytes = args->n_pes_h_s_bytes, 32362306a36Sopenharmony_ci .access_unit_len = args->access_unit_len, 32462306a36Sopenharmony_ci }; 32562306a36Sopenharmony_ci u32 remaining_len = args->access_unit_len; 32662306a36Sopenharmony_ci bool wrote_pes_header = false; 32762306a36Sopenharmony_ci u64 last_pcr = args->pcr; 32862306a36Sopenharmony_ci bool need_pcr = true; 32962306a36Sopenharmony_ci u32 available_space; 33062306a36Sopenharmony_ci u32 payload_size; 33162306a36Sopenharmony_ci u32 stuff_bytes; 33262306a36Sopenharmony_ci u32 nbytes = 0; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if (unaligned_bytes) { 33562306a36Sopenharmony_ci pr_warn_ratelimited("buffer is misaligned, while starting PES\n"); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci /* forcibly align and hope for the best */ 33862306a36Sopenharmony_ci nbytes += vidtv_memset(args->dest_buf, 33962306a36Sopenharmony_ci args->dest_offset + nbytes, 34062306a36Sopenharmony_ci args->dest_buf_sz, 34162306a36Sopenharmony_ci TS_FILL_BYTE, 34262306a36Sopenharmony_ci TS_PACKET_LEN - unaligned_bytes); 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci while (remaining_len) { 34662306a36Sopenharmony_ci available_space = TS_PAYLOAD_LEN; 34762306a36Sopenharmony_ci /* 34862306a36Sopenharmony_ci * The amount of space initially available in the TS packet. 34962306a36Sopenharmony_ci * if this is the beginning of the PES packet, take into account 35062306a36Sopenharmony_ci * the space needed for the TS header _and_ for the PES header 35162306a36Sopenharmony_ci */ 35262306a36Sopenharmony_ci if (!wrote_pes_header) 35362306a36Sopenharmony_ci available_space -= vidtv_pes_h_get_len(args->send_pts, 35462306a36Sopenharmony_ci args->send_dts); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* 35762306a36Sopenharmony_ci * if the encoder has inserted stuffing bytes in the PES 35862306a36Sopenharmony_ci * header, account for them. 35962306a36Sopenharmony_ci */ 36062306a36Sopenharmony_ci available_space -= args->n_pes_h_s_bytes; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci /* Take the extra adaptation into account if need to send PCR */ 36362306a36Sopenharmony_ci if (need_pcr) { 36462306a36Sopenharmony_ci available_space -= SIZE_PCR; 36562306a36Sopenharmony_ci stuff_bytes = SIZE_PCR; 36662306a36Sopenharmony_ci } else { 36762306a36Sopenharmony_ci stuff_bytes = 0; 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci /* 37162306a36Sopenharmony_ci * how much of the _actual_ payload should be written in this 37262306a36Sopenharmony_ci * packet. 37362306a36Sopenharmony_ci */ 37462306a36Sopenharmony_ci if (remaining_len >= available_space) { 37562306a36Sopenharmony_ci payload_size = available_space; 37662306a36Sopenharmony_ci } else { 37762306a36Sopenharmony_ci /* Last frame should ensure 188-bytes PS alignment */ 37862306a36Sopenharmony_ci payload_size = remaining_len; 37962306a36Sopenharmony_ci stuff_bytes += available_space - payload_size; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci /* 38262306a36Sopenharmony_ci * Ensure that the stuff bytes will be within the 38362306a36Sopenharmony_ci * allowed range, decrementing the number of payload 38462306a36Sopenharmony_ci * bytes to write if needed. 38562306a36Sopenharmony_ci */ 38662306a36Sopenharmony_ci if (stuff_bytes > PES_TS_HEADER_MAX_STUFFING_BYTES) { 38762306a36Sopenharmony_ci u32 tmp = stuff_bytes - PES_TS_HEADER_MAX_STUFFING_BYTES; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci stuff_bytes = PES_TS_HEADER_MAX_STUFFING_BYTES; 39062306a36Sopenharmony_ci payload_size -= tmp; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci /* write ts header */ 39562306a36Sopenharmony_ci ts_header_args.dest_offset = args->dest_offset + nbytes; 39662306a36Sopenharmony_ci ts_header_args.wrote_pes_header = wrote_pes_header; 39762306a36Sopenharmony_ci ts_header_args.n_stuffing_bytes = stuff_bytes; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci nbytes += vidtv_pes_write_ts_h(ts_header_args, need_pcr, 40062306a36Sopenharmony_ci &last_pcr); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci need_pcr = false; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (!wrote_pes_header) { 40562306a36Sopenharmony_ci /* write the PES header only once */ 40662306a36Sopenharmony_ci pes_header_args.dest_offset = args->dest_offset + 40762306a36Sopenharmony_ci nbytes; 40862306a36Sopenharmony_ci nbytes += vidtv_pes_write_h(&pes_header_args); 40962306a36Sopenharmony_ci wrote_pes_header = true; 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci /* write as much of the payload as we possibly can */ 41362306a36Sopenharmony_ci nbytes += vidtv_memcpy(args->dest_buf, 41462306a36Sopenharmony_ci args->dest_offset + nbytes, 41562306a36Sopenharmony_ci args->dest_buf_sz, 41662306a36Sopenharmony_ci args->from, 41762306a36Sopenharmony_ci payload_size); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci args->from += payload_size; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci remaining_len -= payload_size; 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci return nbytes; 42562306a36Sopenharmony_ci} 426