18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Vidtv serves as a reference DVB driver and helps validate the existing APIs 48c2ecf20Sopenharmony_ci * in the media subsystem. It can also aid developers working on userspace 58c2ecf20Sopenharmony_ci * applications. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This file contains the logic to translate the ES data for one access unit 88c2ecf20Sopenharmony_ci * from an encoder into MPEG TS packets. It does so by first encapsulating it 98c2ecf20Sopenharmony_ci * with a PES header and then splitting it into TS packets. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Copyright (C) 2020 Daniel W. S. Almeida 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ":%s, %d: " fmt, __func__, __LINE__ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/types.h> 178c2ecf20Sopenharmony_ci#include <linux/printk.h> 188c2ecf20Sopenharmony_ci#include <linux/ratelimit.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "vidtv_pes.h" 218c2ecf20Sopenharmony_ci#include "vidtv_common.h" 228c2ecf20Sopenharmony_ci#include "vidtv_encoder.h" 238c2ecf20Sopenharmony_ci#include "vidtv_ts.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define PRIVATE_STREAM_1_ID 0xbd /* private_stream_1. See SMPTE 302M-2007 p.6 */ 268c2ecf20Sopenharmony_ci#define PES_HEADER_MAX_STUFFING_BYTES 32 278c2ecf20Sopenharmony_ci#define PES_TS_HEADER_MAX_STUFFING_BYTES 182 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic u32 vidtv_pes_op_get_len(bool send_pts, bool send_dts) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci u32 len = 0; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci /* the flags must always be sent */ 348c2ecf20Sopenharmony_ci len += sizeof(struct vidtv_pes_optional); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci /* From all optionals, we might send these for now */ 378c2ecf20Sopenharmony_ci if (send_pts && send_dts) 388c2ecf20Sopenharmony_ci len += sizeof(struct vidtv_pes_optional_pts_dts); 398c2ecf20Sopenharmony_ci else if (send_pts) 408c2ecf20Sopenharmony_ci len += sizeof(struct vidtv_pes_optional_pts); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci return len; 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define SIZE_PCR (6 + sizeof(struct vidtv_mpeg_ts_adaption)) 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic u32 vidtv_pes_h_get_len(bool send_pts, bool send_dts) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci u32 len = 0; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci /* PES header length notwithstanding stuffing bytes */ 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci len += sizeof(struct vidtv_mpeg_pes); 548c2ecf20Sopenharmony_ci len += vidtv_pes_op_get_len(send_pts, send_dts); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci return len; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic u32 vidtv_pes_write_header_stuffing(struct pes_header_write_args *args) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci /* 628c2ecf20Sopenharmony_ci * This is a fixed 8-bit value equal to '0xFF' that can be inserted 638c2ecf20Sopenharmony_ci * by the encoder, for example to meet the requirements of the channel. 648c2ecf20Sopenharmony_ci * It is discarded by the decoder. No more than 32 stuffing bytes shall 658c2ecf20Sopenharmony_ci * be present in one PES packet header. 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_ci if (args->n_pes_h_s_bytes > PES_HEADER_MAX_STUFFING_BYTES) { 688c2ecf20Sopenharmony_ci pr_warn_ratelimited("More than %d stuffing bytes in PES packet header\n", 698c2ecf20Sopenharmony_ci PES_HEADER_MAX_STUFFING_BYTES); 708c2ecf20Sopenharmony_ci args->n_pes_h_s_bytes = PES_HEADER_MAX_STUFFING_BYTES; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci return vidtv_memset(args->dest_buf, 748c2ecf20Sopenharmony_ci args->dest_offset, 758c2ecf20Sopenharmony_ci args->dest_buf_sz, 768c2ecf20Sopenharmony_ci TS_FILL_BYTE, 778c2ecf20Sopenharmony_ci args->n_pes_h_s_bytes); 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic u32 vidtv_pes_write_pts_dts(struct pes_header_write_args *args) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci u32 nbytes = 0; /* the number of bytes written by this function */ 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci struct vidtv_pes_optional_pts pts = {}; 858c2ecf20Sopenharmony_ci struct vidtv_pes_optional_pts_dts pts_dts = {}; 868c2ecf20Sopenharmony_ci void *op = NULL; 878c2ecf20Sopenharmony_ci size_t op_sz = 0; 888c2ecf20Sopenharmony_ci u64 mask1; 898c2ecf20Sopenharmony_ci u64 mask2; 908c2ecf20Sopenharmony_ci u64 mask3; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci if (!args->send_pts && args->send_dts) 938c2ecf20Sopenharmony_ci return 0; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci mask1 = GENMASK_ULL(32, 30); 968c2ecf20Sopenharmony_ci mask2 = GENMASK_ULL(29, 15); 978c2ecf20Sopenharmony_ci mask3 = GENMASK_ULL(14, 0); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci /* see ISO/IEC 13818-1 : 2000 p. 32 */ 1008c2ecf20Sopenharmony_ci if (args->send_pts && args->send_dts) { 1018c2ecf20Sopenharmony_ci pts_dts.pts1 = (0x3 << 4) | ((args->pts & mask1) >> 29) | 0x1; 1028c2ecf20Sopenharmony_ci pts_dts.pts2 = cpu_to_be16(((args->pts & mask2) >> 14) | 0x1); 1038c2ecf20Sopenharmony_ci pts_dts.pts3 = cpu_to_be16(((args->pts & mask3) << 1) | 0x1); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci pts_dts.dts1 = (0x1 << 4) | ((args->dts & mask1) >> 29) | 0x1; 1068c2ecf20Sopenharmony_ci pts_dts.dts2 = cpu_to_be16(((args->dts & mask2) >> 14) | 0x1); 1078c2ecf20Sopenharmony_ci pts_dts.dts3 = cpu_to_be16(((args->dts & mask3) << 1) | 0x1); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci op = &pts_dts; 1108c2ecf20Sopenharmony_ci op_sz = sizeof(pts_dts); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci } else if (args->send_pts) { 1138c2ecf20Sopenharmony_ci pts.pts1 = (0x1 << 5) | ((args->pts & mask1) >> 29) | 0x1; 1148c2ecf20Sopenharmony_ci pts.pts2 = cpu_to_be16(((args->pts & mask2) >> 14) | 0x1); 1158c2ecf20Sopenharmony_ci pts.pts3 = cpu_to_be16(((args->pts & mask3) << 1) | 0x1); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci op = &pts; 1188c2ecf20Sopenharmony_ci op_sz = sizeof(pts); 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci /* copy PTS/DTS optional */ 1228c2ecf20Sopenharmony_ci nbytes += vidtv_memcpy(args->dest_buf, 1238c2ecf20Sopenharmony_ci args->dest_offset + nbytes, 1248c2ecf20Sopenharmony_ci args->dest_buf_sz, 1258c2ecf20Sopenharmony_ci op, 1268c2ecf20Sopenharmony_ci op_sz); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci return nbytes; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic u32 vidtv_pes_write_h(struct pes_header_write_args *args) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci u32 nbytes = 0; /* the number of bytes written by this function */ 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci struct vidtv_mpeg_pes pes_header = {}; 1368c2ecf20Sopenharmony_ci struct vidtv_pes_optional pes_optional = {}; 1378c2ecf20Sopenharmony_ci struct pes_header_write_args pts_dts_args; 1388c2ecf20Sopenharmony_ci u32 stream_id = (args->encoder_id == S302M) ? PRIVATE_STREAM_1_ID : args->stream_id; 1398c2ecf20Sopenharmony_ci u16 pes_opt_bitfield = 0x01 << 15; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci pes_header.bitfield = cpu_to_be32((PES_START_CODE_PREFIX << 8) | stream_id); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci pes_header.length = cpu_to_be16(vidtv_pes_op_get_len(args->send_pts, 1448c2ecf20Sopenharmony_ci args->send_dts) + 1458c2ecf20Sopenharmony_ci args->access_unit_len); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci if (args->send_pts && args->send_dts) 1488c2ecf20Sopenharmony_ci pes_opt_bitfield |= (0x3 << 6); 1498c2ecf20Sopenharmony_ci else if (args->send_pts) 1508c2ecf20Sopenharmony_ci pes_opt_bitfield |= (0x1 << 7); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci pes_optional.bitfield = cpu_to_be16(pes_opt_bitfield); 1538c2ecf20Sopenharmony_ci pes_optional.length = vidtv_pes_op_get_len(args->send_pts, args->send_dts) + 1548c2ecf20Sopenharmony_ci args->n_pes_h_s_bytes - 1558c2ecf20Sopenharmony_ci sizeof(struct vidtv_pes_optional); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci /* copy header */ 1588c2ecf20Sopenharmony_ci nbytes += vidtv_memcpy(args->dest_buf, 1598c2ecf20Sopenharmony_ci args->dest_offset + nbytes, 1608c2ecf20Sopenharmony_ci args->dest_buf_sz, 1618c2ecf20Sopenharmony_ci &pes_header, 1628c2ecf20Sopenharmony_ci sizeof(pes_header)); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci /* copy optional header bits */ 1658c2ecf20Sopenharmony_ci nbytes += vidtv_memcpy(args->dest_buf, 1668c2ecf20Sopenharmony_ci args->dest_offset + nbytes, 1678c2ecf20Sopenharmony_ci args->dest_buf_sz, 1688c2ecf20Sopenharmony_ci &pes_optional, 1698c2ecf20Sopenharmony_ci sizeof(pes_optional)); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* copy the timing information */ 1728c2ecf20Sopenharmony_ci pts_dts_args = *args; 1738c2ecf20Sopenharmony_ci pts_dts_args.dest_offset = args->dest_offset + nbytes; 1748c2ecf20Sopenharmony_ci nbytes += vidtv_pes_write_pts_dts(&pts_dts_args); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci /* write any PES header stuffing */ 1778c2ecf20Sopenharmony_ci nbytes += vidtv_pes_write_header_stuffing(args); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci return nbytes; 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cistatic u32 vidtv_pes_write_pcr_bits(u8 *to, u32 to_offset, u64 pcr) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci /* Exact same from ffmpeg. PCR is a counter driven by a 27Mhz clock */ 1858c2ecf20Sopenharmony_ci u64 div; 1868c2ecf20Sopenharmony_ci u64 rem; 1878c2ecf20Sopenharmony_ci u8 *buf = to + to_offset; 1888c2ecf20Sopenharmony_ci u64 pcr_low; 1898c2ecf20Sopenharmony_ci u64 pcr_high; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci div = div64_u64_rem(pcr, 300, &rem); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci pcr_low = rem; /* pcr_low = pcr % 300 */ 1948c2ecf20Sopenharmony_ci pcr_high = div; /* pcr_high = pcr / 300 */ 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci *buf++ = pcr_high >> 25; 1978c2ecf20Sopenharmony_ci *buf++ = pcr_high >> 17; 1988c2ecf20Sopenharmony_ci *buf++ = pcr_high >> 9; 1998c2ecf20Sopenharmony_ci *buf++ = pcr_high >> 1; 2008c2ecf20Sopenharmony_ci *buf++ = pcr_high << 7 | pcr_low >> 8 | 0x7e; 2018c2ecf20Sopenharmony_ci *buf++ = pcr_low; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci return 6; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic u32 vidtv_pes_write_stuffing(struct pes_ts_header_write_args *args, 2078c2ecf20Sopenharmony_ci u32 dest_offset, bool need_pcr, 2088c2ecf20Sopenharmony_ci u64 *last_pcr) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci struct vidtv_mpeg_ts_adaption ts_adap = {}; 2118c2ecf20Sopenharmony_ci int stuff_nbytes; 2128c2ecf20Sopenharmony_ci u32 nbytes = 0; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci if (!args->n_stuffing_bytes) 2158c2ecf20Sopenharmony_ci return 0; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci ts_adap.random_access = 1; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /* length _immediately_ following 'adaptation_field_length' */ 2208c2ecf20Sopenharmony_ci if (need_pcr) { 2218c2ecf20Sopenharmony_ci ts_adap.PCR = 1; 2228c2ecf20Sopenharmony_ci ts_adap.length = SIZE_PCR; 2238c2ecf20Sopenharmony_ci } else { 2248c2ecf20Sopenharmony_ci ts_adap.length = sizeof(ts_adap); 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci stuff_nbytes = args->n_stuffing_bytes - ts_adap.length; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci ts_adap.length -= sizeof(ts_adap.length); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if (unlikely(stuff_nbytes < 0)) 2318c2ecf20Sopenharmony_ci stuff_nbytes = 0; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci ts_adap.length += stuff_nbytes; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci /* write the adap after the TS header */ 2368c2ecf20Sopenharmony_ci nbytes += vidtv_memcpy(args->dest_buf, 2378c2ecf20Sopenharmony_ci dest_offset + nbytes, 2388c2ecf20Sopenharmony_ci args->dest_buf_sz, 2398c2ecf20Sopenharmony_ci &ts_adap, 2408c2ecf20Sopenharmony_ci sizeof(ts_adap)); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci /* write the optional PCR */ 2438c2ecf20Sopenharmony_ci if (need_pcr) { 2448c2ecf20Sopenharmony_ci nbytes += vidtv_pes_write_pcr_bits(args->dest_buf, 2458c2ecf20Sopenharmony_ci dest_offset + nbytes, 2468c2ecf20Sopenharmony_ci args->pcr); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci *last_pcr = args->pcr; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci /* write the stuffing bytes, if are there anything left */ 2528c2ecf20Sopenharmony_ci if (stuff_nbytes) 2538c2ecf20Sopenharmony_ci nbytes += vidtv_memset(args->dest_buf, 2548c2ecf20Sopenharmony_ci dest_offset + nbytes, 2558c2ecf20Sopenharmony_ci args->dest_buf_sz, 2568c2ecf20Sopenharmony_ci TS_FILL_BYTE, 2578c2ecf20Sopenharmony_ci stuff_nbytes); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci /* 2608c2ecf20Sopenharmony_ci * The n_stuffing_bytes contain a pre-calculated value of 2618c2ecf20Sopenharmony_ci * the amount of data that this function would read, made from 2628c2ecf20Sopenharmony_ci * vidtv_pes_h_get_len(). If something went wrong, print a warning 2638c2ecf20Sopenharmony_ci */ 2648c2ecf20Sopenharmony_ci if (nbytes != args->n_stuffing_bytes) 2658c2ecf20Sopenharmony_ci pr_warn_ratelimited("write size was %d, expected %d\n", 2668c2ecf20Sopenharmony_ci nbytes, args->n_stuffing_bytes); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci return nbytes; 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic u32 vidtv_pes_write_ts_h(struct pes_ts_header_write_args args, 2728c2ecf20Sopenharmony_ci bool need_pcr, u64 *last_pcr) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci /* number of bytes written by this function */ 2758c2ecf20Sopenharmony_ci u32 nbytes = 0; 2768c2ecf20Sopenharmony_ci struct vidtv_mpeg_ts ts_header = {}; 2778c2ecf20Sopenharmony_ci u16 payload_start = !args.wrote_pes_header; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci ts_header.sync_byte = TS_SYNC_BYTE; 2808c2ecf20Sopenharmony_ci ts_header.bitfield = cpu_to_be16((payload_start << 14) | args.pid); 2818c2ecf20Sopenharmony_ci ts_header.scrambling = 0; 2828c2ecf20Sopenharmony_ci ts_header.adaptation_field = (args.n_stuffing_bytes) > 0; 2838c2ecf20Sopenharmony_ci ts_header.payload = (args.n_stuffing_bytes) < PES_TS_HEADER_MAX_STUFFING_BYTES; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci ts_header.continuity_counter = *args.continuity_counter; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci vidtv_ts_inc_cc(args.continuity_counter); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci /* write the TS header */ 2908c2ecf20Sopenharmony_ci nbytes += vidtv_memcpy(args.dest_buf, 2918c2ecf20Sopenharmony_ci args.dest_offset + nbytes, 2928c2ecf20Sopenharmony_ci args.dest_buf_sz, 2938c2ecf20Sopenharmony_ci &ts_header, 2948c2ecf20Sopenharmony_ci sizeof(ts_header)); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci /* write stuffing, if any */ 2978c2ecf20Sopenharmony_ci nbytes += vidtv_pes_write_stuffing(&args, args.dest_offset + nbytes, 2988c2ecf20Sopenharmony_ci need_pcr, last_pcr); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci return nbytes; 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ciu32 vidtv_pes_write_into(struct pes_write_args *args) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci u32 unaligned_bytes = (args->dest_offset % TS_PACKET_LEN); 3068c2ecf20Sopenharmony_ci struct pes_ts_header_write_args ts_header_args = { 3078c2ecf20Sopenharmony_ci .dest_buf = args->dest_buf, 3088c2ecf20Sopenharmony_ci .dest_buf_sz = args->dest_buf_sz, 3098c2ecf20Sopenharmony_ci .pid = args->pid, 3108c2ecf20Sopenharmony_ci .pcr = args->pcr, 3118c2ecf20Sopenharmony_ci .continuity_counter = args->continuity_counter, 3128c2ecf20Sopenharmony_ci }; 3138c2ecf20Sopenharmony_ci struct pes_header_write_args pes_header_args = { 3148c2ecf20Sopenharmony_ci .dest_buf = args->dest_buf, 3158c2ecf20Sopenharmony_ci .dest_buf_sz = args->dest_buf_sz, 3168c2ecf20Sopenharmony_ci .encoder_id = args->encoder_id, 3178c2ecf20Sopenharmony_ci .send_pts = args->send_pts, 3188c2ecf20Sopenharmony_ci .pts = args->pts, 3198c2ecf20Sopenharmony_ci .send_dts = args->send_dts, 3208c2ecf20Sopenharmony_ci .dts = args->dts, 3218c2ecf20Sopenharmony_ci .stream_id = args->stream_id, 3228c2ecf20Sopenharmony_ci .n_pes_h_s_bytes = args->n_pes_h_s_bytes, 3238c2ecf20Sopenharmony_ci .access_unit_len = args->access_unit_len, 3248c2ecf20Sopenharmony_ci }; 3258c2ecf20Sopenharmony_ci u32 remaining_len = args->access_unit_len; 3268c2ecf20Sopenharmony_ci bool wrote_pes_header = false; 3278c2ecf20Sopenharmony_ci u64 last_pcr = args->pcr; 3288c2ecf20Sopenharmony_ci bool need_pcr = true; 3298c2ecf20Sopenharmony_ci u32 available_space; 3308c2ecf20Sopenharmony_ci u32 payload_size; 3318c2ecf20Sopenharmony_ci u32 stuff_bytes; 3328c2ecf20Sopenharmony_ci u32 nbytes = 0; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (unaligned_bytes) { 3358c2ecf20Sopenharmony_ci pr_warn_ratelimited("buffer is misaligned, while starting PES\n"); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci /* forcibly align and hope for the best */ 3388c2ecf20Sopenharmony_ci nbytes += vidtv_memset(args->dest_buf, 3398c2ecf20Sopenharmony_ci args->dest_offset + nbytes, 3408c2ecf20Sopenharmony_ci args->dest_buf_sz, 3418c2ecf20Sopenharmony_ci TS_FILL_BYTE, 3428c2ecf20Sopenharmony_ci TS_PACKET_LEN - unaligned_bytes); 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci while (remaining_len) { 3468c2ecf20Sopenharmony_ci available_space = TS_PAYLOAD_LEN; 3478c2ecf20Sopenharmony_ci /* 3488c2ecf20Sopenharmony_ci * The amount of space initially available in the TS packet. 3498c2ecf20Sopenharmony_ci * if this is the beginning of the PES packet, take into account 3508c2ecf20Sopenharmony_ci * the space needed for the TS header _and_ for the PES header 3518c2ecf20Sopenharmony_ci */ 3528c2ecf20Sopenharmony_ci if (!wrote_pes_header) 3538c2ecf20Sopenharmony_ci available_space -= vidtv_pes_h_get_len(args->send_pts, 3548c2ecf20Sopenharmony_ci args->send_dts); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci /* 3578c2ecf20Sopenharmony_ci * if the encoder has inserted stuffing bytes in the PES 3588c2ecf20Sopenharmony_ci * header, account for them. 3598c2ecf20Sopenharmony_ci */ 3608c2ecf20Sopenharmony_ci available_space -= args->n_pes_h_s_bytes; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci /* Take the extra adaptation into account if need to send PCR */ 3638c2ecf20Sopenharmony_ci if (need_pcr) { 3648c2ecf20Sopenharmony_ci available_space -= SIZE_PCR; 3658c2ecf20Sopenharmony_ci stuff_bytes = SIZE_PCR; 3668c2ecf20Sopenharmony_ci } else { 3678c2ecf20Sopenharmony_ci stuff_bytes = 0; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci /* 3718c2ecf20Sopenharmony_ci * how much of the _actual_ payload should be written in this 3728c2ecf20Sopenharmony_ci * packet. 3738c2ecf20Sopenharmony_ci */ 3748c2ecf20Sopenharmony_ci if (remaining_len >= available_space) { 3758c2ecf20Sopenharmony_ci payload_size = available_space; 3768c2ecf20Sopenharmony_ci } else { 3778c2ecf20Sopenharmony_ci /* Last frame should ensure 188-bytes PS alignment */ 3788c2ecf20Sopenharmony_ci payload_size = remaining_len; 3798c2ecf20Sopenharmony_ci stuff_bytes += available_space - payload_size; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /* 3828c2ecf20Sopenharmony_ci * Ensure that the stuff bytes will be within the 3838c2ecf20Sopenharmony_ci * allowed range, decrementing the number of payload 3848c2ecf20Sopenharmony_ci * bytes to write if needed. 3858c2ecf20Sopenharmony_ci */ 3868c2ecf20Sopenharmony_ci if (stuff_bytes > PES_TS_HEADER_MAX_STUFFING_BYTES) { 3878c2ecf20Sopenharmony_ci u32 tmp = stuff_bytes - PES_TS_HEADER_MAX_STUFFING_BYTES; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci stuff_bytes = PES_TS_HEADER_MAX_STUFFING_BYTES; 3908c2ecf20Sopenharmony_ci payload_size -= tmp; 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci /* write ts header */ 3958c2ecf20Sopenharmony_ci ts_header_args.dest_offset = args->dest_offset + nbytes; 3968c2ecf20Sopenharmony_ci ts_header_args.wrote_pes_header = wrote_pes_header; 3978c2ecf20Sopenharmony_ci ts_header_args.n_stuffing_bytes = stuff_bytes; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci nbytes += vidtv_pes_write_ts_h(ts_header_args, need_pcr, 4008c2ecf20Sopenharmony_ci &last_pcr); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci need_pcr = false; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci if (!wrote_pes_header) { 4058c2ecf20Sopenharmony_ci /* write the PES header only once */ 4068c2ecf20Sopenharmony_ci pes_header_args.dest_offset = args->dest_offset + 4078c2ecf20Sopenharmony_ci nbytes; 4088c2ecf20Sopenharmony_ci nbytes += vidtv_pes_write_h(&pes_header_args); 4098c2ecf20Sopenharmony_ci wrote_pes_header = true; 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci /* write as much of the payload as we possibly can */ 4138c2ecf20Sopenharmony_ci nbytes += vidtv_memcpy(args->dest_buf, 4148c2ecf20Sopenharmony_ci args->dest_offset + nbytes, 4158c2ecf20Sopenharmony_ci args->dest_buf_sz, 4168c2ecf20Sopenharmony_ci args->from, 4178c2ecf20Sopenharmony_ci payload_size); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci args->from += payload_size; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci remaining_len -= payload_size; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci return nbytes; 4258c2ecf20Sopenharmony_ci} 426