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 multiplexer logic for TS packets from different 88c2ecf20Sopenharmony_ci * elementary streams 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Loosely based on libavcodec/mpegtsenc.c 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Copyright (C) 2020 Daniel W. S. Almeida 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/delay.h> 168c2ecf20Sopenharmony_ci#include <linux/dev_printk.h> 178c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 188c2ecf20Sopenharmony_ci#include <linux/kernel.h> 198c2ecf20Sopenharmony_ci#include <linux/math64.h> 208c2ecf20Sopenharmony_ci#include <linux/ratelimit.h> 218c2ecf20Sopenharmony_ci#include <linux/slab.h> 228c2ecf20Sopenharmony_ci#include <linux/types.h> 238c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include "vidtv_channel.h" 268c2ecf20Sopenharmony_ci#include "vidtv_common.h" 278c2ecf20Sopenharmony_ci#include "vidtv_encoder.h" 288c2ecf20Sopenharmony_ci#include "vidtv_mux.h" 298c2ecf20Sopenharmony_ci#include "vidtv_pes.h" 308c2ecf20Sopenharmony_ci#include "vidtv_psi.h" 318c2ecf20Sopenharmony_ci#include "vidtv_ts.h" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic struct vidtv_mux_pid_ctx 348c2ecf20Sopenharmony_ci*vidtv_mux_get_pid_ctx(struct vidtv_mux *m, u16 pid) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci struct vidtv_mux_pid_ctx *ctx; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci hash_for_each_possible(m->pid_ctx, ctx, h, pid) 398c2ecf20Sopenharmony_ci if (ctx->pid == pid) 408c2ecf20Sopenharmony_ci return ctx; 418c2ecf20Sopenharmony_ci return NULL; 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic struct vidtv_mux_pid_ctx 458c2ecf20Sopenharmony_ci*vidtv_mux_create_pid_ctx_once(struct vidtv_mux *m, u16 pid) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci struct vidtv_mux_pid_ctx *ctx; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci ctx = vidtv_mux_get_pid_ctx(m, pid); 508c2ecf20Sopenharmony_ci if (ctx) 518c2ecf20Sopenharmony_ci return ctx; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 548c2ecf20Sopenharmony_ci if (!ctx) 558c2ecf20Sopenharmony_ci return NULL; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci ctx->pid = pid; 588c2ecf20Sopenharmony_ci ctx->cc = 0; 598c2ecf20Sopenharmony_ci hash_add(m->pid_ctx, &ctx->h, pid); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci return ctx; 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic void vidtv_mux_pid_ctx_destroy(struct vidtv_mux *m) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci struct vidtv_mux_pid_ctx *ctx; 678c2ecf20Sopenharmony_ci struct hlist_node *tmp; 688c2ecf20Sopenharmony_ci int bkt; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci hash_for_each_safe(m->pid_ctx, bkt, tmp, ctx, h) { 718c2ecf20Sopenharmony_ci hash_del(&ctx->h); 728c2ecf20Sopenharmony_ci kfree(ctx); 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic int vidtv_mux_pid_ctx_init(struct vidtv_mux *m) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci struct vidtv_psi_table_pat_program *p = m->si.pat->program; 798c2ecf20Sopenharmony_ci u16 pid; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci hash_init(m->pid_ctx); 828c2ecf20Sopenharmony_ci /* push the pcr pid ctx */ 838c2ecf20Sopenharmony_ci if (!vidtv_mux_create_pid_ctx_once(m, m->pcr_pid)) 848c2ecf20Sopenharmony_ci return -ENOMEM; 858c2ecf20Sopenharmony_ci /* push the NULL packet pid ctx */ 868c2ecf20Sopenharmony_ci if (!vidtv_mux_create_pid_ctx_once(m, TS_NULL_PACKET_PID)) 878c2ecf20Sopenharmony_ci goto free; 888c2ecf20Sopenharmony_ci /* push the PAT pid ctx */ 898c2ecf20Sopenharmony_ci if (!vidtv_mux_create_pid_ctx_once(m, VIDTV_PAT_PID)) 908c2ecf20Sopenharmony_ci goto free; 918c2ecf20Sopenharmony_ci /* push the SDT pid ctx */ 928c2ecf20Sopenharmony_ci if (!vidtv_mux_create_pid_ctx_once(m, VIDTV_SDT_PID)) 938c2ecf20Sopenharmony_ci goto free; 948c2ecf20Sopenharmony_ci /* push the NIT pid ctx */ 958c2ecf20Sopenharmony_ci if (!vidtv_mux_create_pid_ctx_once(m, VIDTV_NIT_PID)) 968c2ecf20Sopenharmony_ci goto free; 978c2ecf20Sopenharmony_ci /* push the EIT pid ctx */ 988c2ecf20Sopenharmony_ci if (!vidtv_mux_create_pid_ctx_once(m, VIDTV_EIT_PID)) 998c2ecf20Sopenharmony_ci goto free; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* add a ctx for all PMT sections */ 1028c2ecf20Sopenharmony_ci while (p) { 1038c2ecf20Sopenharmony_ci pid = vidtv_psi_get_pat_program_pid(p); 1048c2ecf20Sopenharmony_ci vidtv_mux_create_pid_ctx_once(m, pid); 1058c2ecf20Sopenharmony_ci p = p->next; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci return 0; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cifree: 1118c2ecf20Sopenharmony_ci vidtv_mux_pid_ctx_destroy(m); 1128c2ecf20Sopenharmony_ci return -ENOMEM; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic void vidtv_mux_update_clk(struct vidtv_mux *m) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci /* call this at every thread iteration */ 1188c2ecf20Sopenharmony_ci u64 elapsed_time; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci m->timing.past_jiffies = m->timing.current_jiffies; 1218c2ecf20Sopenharmony_ci m->timing.current_jiffies = get_jiffies_64(); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci elapsed_time = jiffies_to_usecs(m->timing.current_jiffies - 1248c2ecf20Sopenharmony_ci m->timing.past_jiffies); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci /* update the 27Mhz clock proportionally to the elapsed time */ 1278c2ecf20Sopenharmony_ci m->timing.clk += (CLOCK_UNIT_27MHZ / USEC_PER_SEC) * elapsed_time; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic u32 vidtv_mux_push_si(struct vidtv_mux *m) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci struct vidtv_psi_pat_write_args pat_args = { 1338c2ecf20Sopenharmony_ci .buf = m->mux_buf, 1348c2ecf20Sopenharmony_ci .buf_sz = m->mux_buf_sz, 1358c2ecf20Sopenharmony_ci .pat = m->si.pat, 1368c2ecf20Sopenharmony_ci }; 1378c2ecf20Sopenharmony_ci struct vidtv_psi_pmt_write_args pmt_args = { 1388c2ecf20Sopenharmony_ci .buf = m->mux_buf, 1398c2ecf20Sopenharmony_ci .buf_sz = m->mux_buf_sz, 1408c2ecf20Sopenharmony_ci .pcr_pid = m->pcr_pid, 1418c2ecf20Sopenharmony_ci }; 1428c2ecf20Sopenharmony_ci struct vidtv_psi_sdt_write_args sdt_args = { 1438c2ecf20Sopenharmony_ci .buf = m->mux_buf, 1448c2ecf20Sopenharmony_ci .buf_sz = m->mux_buf_sz, 1458c2ecf20Sopenharmony_ci .sdt = m->si.sdt, 1468c2ecf20Sopenharmony_ci }; 1478c2ecf20Sopenharmony_ci struct vidtv_psi_nit_write_args nit_args = { 1488c2ecf20Sopenharmony_ci .buf = m->mux_buf, 1498c2ecf20Sopenharmony_ci .buf_sz = m->mux_buf_sz, 1508c2ecf20Sopenharmony_ci .nit = m->si.nit, 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci }; 1538c2ecf20Sopenharmony_ci struct vidtv_psi_eit_write_args eit_args = { 1548c2ecf20Sopenharmony_ci .buf = m->mux_buf, 1558c2ecf20Sopenharmony_ci .buf_sz = m->mux_buf_sz, 1568c2ecf20Sopenharmony_ci .eit = m->si.eit, 1578c2ecf20Sopenharmony_ci }; 1588c2ecf20Sopenharmony_ci u32 initial_offset = m->mux_buf_offset; 1598c2ecf20Sopenharmony_ci struct vidtv_mux_pid_ctx *pat_ctx; 1608c2ecf20Sopenharmony_ci struct vidtv_mux_pid_ctx *pmt_ctx; 1618c2ecf20Sopenharmony_ci struct vidtv_mux_pid_ctx *sdt_ctx; 1628c2ecf20Sopenharmony_ci struct vidtv_mux_pid_ctx *nit_ctx; 1638c2ecf20Sopenharmony_ci struct vidtv_mux_pid_ctx *eit_ctx; 1648c2ecf20Sopenharmony_ci u32 nbytes; 1658c2ecf20Sopenharmony_ci u16 pmt_pid; 1668c2ecf20Sopenharmony_ci u32 i; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci pat_ctx = vidtv_mux_get_pid_ctx(m, VIDTV_PAT_PID); 1698c2ecf20Sopenharmony_ci sdt_ctx = vidtv_mux_get_pid_ctx(m, VIDTV_SDT_PID); 1708c2ecf20Sopenharmony_ci nit_ctx = vidtv_mux_get_pid_ctx(m, VIDTV_NIT_PID); 1718c2ecf20Sopenharmony_ci eit_ctx = vidtv_mux_get_pid_ctx(m, VIDTV_EIT_PID); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci pat_args.offset = m->mux_buf_offset; 1748c2ecf20Sopenharmony_ci pat_args.continuity_counter = &pat_ctx->cc; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci m->mux_buf_offset += vidtv_psi_pat_write_into(&pat_args); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci for (i = 0; i < m->si.pat->num_pmt; ++i) { 1798c2ecf20Sopenharmony_ci pmt_pid = vidtv_psi_pmt_get_pid(m->si.pmt_secs[i], 1808c2ecf20Sopenharmony_ci m->si.pat); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci if (pmt_pid > TS_LAST_VALID_PID) { 1838c2ecf20Sopenharmony_ci dev_warn_ratelimited(m->dev, 1848c2ecf20Sopenharmony_ci "PID: %d not found\n", pmt_pid); 1858c2ecf20Sopenharmony_ci continue; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci pmt_ctx = vidtv_mux_get_pid_ctx(m, pmt_pid); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci pmt_args.offset = m->mux_buf_offset; 1918c2ecf20Sopenharmony_ci pmt_args.pmt = m->si.pmt_secs[i]; 1928c2ecf20Sopenharmony_ci pmt_args.pid = pmt_pid; 1938c2ecf20Sopenharmony_ci pmt_args.continuity_counter = &pmt_ctx->cc; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci /* write each section into buffer */ 1968c2ecf20Sopenharmony_ci m->mux_buf_offset += vidtv_psi_pmt_write_into(&pmt_args); 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci sdt_args.offset = m->mux_buf_offset; 2008c2ecf20Sopenharmony_ci sdt_args.continuity_counter = &sdt_ctx->cc; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci m->mux_buf_offset += vidtv_psi_sdt_write_into(&sdt_args); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci nit_args.offset = m->mux_buf_offset; 2058c2ecf20Sopenharmony_ci nit_args.continuity_counter = &nit_ctx->cc; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci m->mux_buf_offset += vidtv_psi_nit_write_into(&nit_args); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci eit_args.offset = m->mux_buf_offset; 2108c2ecf20Sopenharmony_ci eit_args.continuity_counter = &eit_ctx->cc; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci m->mux_buf_offset += vidtv_psi_eit_write_into(&eit_args); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci nbytes = m->mux_buf_offset - initial_offset; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci m->num_streamed_si++; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci return nbytes; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic u32 vidtv_mux_push_pcr(struct vidtv_mux *m) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci struct pcr_write_args args = {}; 2248c2ecf20Sopenharmony_ci struct vidtv_mux_pid_ctx *ctx; 2258c2ecf20Sopenharmony_ci u32 nbytes = 0; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci ctx = vidtv_mux_get_pid_ctx(m, m->pcr_pid); 2288c2ecf20Sopenharmony_ci args.dest_buf = m->mux_buf; 2298c2ecf20Sopenharmony_ci args.pid = m->pcr_pid; 2308c2ecf20Sopenharmony_ci args.buf_sz = m->mux_buf_sz; 2318c2ecf20Sopenharmony_ci args.continuity_counter = &ctx->cc; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci /* the 27Mhz clock will feed both parts of the PCR bitfield */ 2348c2ecf20Sopenharmony_ci args.pcr = m->timing.clk; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci nbytes += vidtv_ts_pcr_write_into(args); 2378c2ecf20Sopenharmony_ci m->mux_buf_offset += nbytes; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci m->num_streamed_pcr++; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci return nbytes; 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic bool vidtv_mux_should_push_pcr(struct vidtv_mux *m) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci u64 next_pcr_at; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (m->num_streamed_pcr == 0) 2498c2ecf20Sopenharmony_ci return true; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci next_pcr_at = m->timing.start_jiffies + 2528c2ecf20Sopenharmony_ci usecs_to_jiffies(m->num_streamed_pcr * 2538c2ecf20Sopenharmony_ci m->timing.pcr_period_usecs); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci return time_after64(m->timing.current_jiffies, next_pcr_at); 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic bool vidtv_mux_should_push_si(struct vidtv_mux *m) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci u64 next_si_at; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci if (m->num_streamed_si == 0) 2638c2ecf20Sopenharmony_ci return true; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci next_si_at = m->timing.start_jiffies + 2668c2ecf20Sopenharmony_ci usecs_to_jiffies(m->num_streamed_si * 2678c2ecf20Sopenharmony_ci m->timing.si_period_usecs); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci return time_after64(m->timing.current_jiffies, next_si_at); 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic u32 vidtv_mux_packetize_access_units(struct vidtv_mux *m, 2738c2ecf20Sopenharmony_ci struct vidtv_encoder *e) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci struct pes_write_args args = { 2768c2ecf20Sopenharmony_ci .dest_buf = m->mux_buf, 2778c2ecf20Sopenharmony_ci .dest_buf_sz = m->mux_buf_sz, 2788c2ecf20Sopenharmony_ci .pid = be16_to_cpu(e->es_pid), 2798c2ecf20Sopenharmony_ci .encoder_id = e->id, 2808c2ecf20Sopenharmony_ci .stream_id = be16_to_cpu(e->stream_id), 2818c2ecf20Sopenharmony_ci .send_pts = true, /* forbidden value '01'... */ 2828c2ecf20Sopenharmony_ci .send_dts = false, /* ...for PTS_DTS flags */ 2838c2ecf20Sopenharmony_ci }; 2848c2ecf20Sopenharmony_ci struct vidtv_access_unit *au = e->access_units; 2858c2ecf20Sopenharmony_ci u32 initial_offset = m->mux_buf_offset; 2868c2ecf20Sopenharmony_ci struct vidtv_mux_pid_ctx *pid_ctx; 2878c2ecf20Sopenharmony_ci u32 nbytes = 0; 2888c2ecf20Sopenharmony_ci u8 *buf = NULL; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* see SMPTE 302M clause 6.4 */ 2918c2ecf20Sopenharmony_ci if (args.encoder_id == S302M) { 2928c2ecf20Sopenharmony_ci args.send_dts = false; 2938c2ecf20Sopenharmony_ci args.send_pts = true; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci pid_ctx = vidtv_mux_create_pid_ctx_once(m, be16_to_cpu(e->es_pid)); 2978c2ecf20Sopenharmony_ci args.continuity_counter = &pid_ctx->cc; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci while (au) { 3008c2ecf20Sopenharmony_ci buf = e->encoder_buf + au->offset; 3018c2ecf20Sopenharmony_ci args.from = buf; 3028c2ecf20Sopenharmony_ci args.access_unit_len = au->nbytes; 3038c2ecf20Sopenharmony_ci args.dest_offset = m->mux_buf_offset; 3048c2ecf20Sopenharmony_ci args.pts = au->pts; 3058c2ecf20Sopenharmony_ci args.pcr = m->timing.clk; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci m->mux_buf_offset += vidtv_pes_write_into(&args); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci au = au->next; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci /* 3138c2ecf20Sopenharmony_ci * clear the encoder state once the ES data has been written to the mux 3148c2ecf20Sopenharmony_ci * buffer 3158c2ecf20Sopenharmony_ci */ 3168c2ecf20Sopenharmony_ci e->clear(e); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci nbytes = m->mux_buf_offset - initial_offset; 3198c2ecf20Sopenharmony_ci return nbytes; 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic u32 vidtv_mux_poll_encoders(struct vidtv_mux *m) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci struct vidtv_channel *cur_chnl = m->channels; 3258c2ecf20Sopenharmony_ci struct vidtv_encoder *e = NULL; 3268c2ecf20Sopenharmony_ci u32 nbytes = 0; 3278c2ecf20Sopenharmony_ci u32 au_nbytes; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci while (cur_chnl) { 3308c2ecf20Sopenharmony_ci e = cur_chnl->encoders; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci while (e) { 3338c2ecf20Sopenharmony_ci e->encode(e); 3348c2ecf20Sopenharmony_ci /* get the TS packets into the mux buffer */ 3358c2ecf20Sopenharmony_ci au_nbytes = vidtv_mux_packetize_access_units(m, e); 3368c2ecf20Sopenharmony_ci nbytes += au_nbytes; 3378c2ecf20Sopenharmony_ci m->mux_buf_offset += au_nbytes; 3388c2ecf20Sopenharmony_ci /* grab next encoder */ 3398c2ecf20Sopenharmony_ci e = e->next; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci /* grab the next channel */ 3438c2ecf20Sopenharmony_ci cur_chnl = cur_chnl->next; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci return nbytes; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic u32 vidtv_mux_pad_with_nulls(struct vidtv_mux *m, u32 npkts) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci struct null_packet_write_args args = { 3528c2ecf20Sopenharmony_ci .dest_buf = m->mux_buf, 3538c2ecf20Sopenharmony_ci .buf_sz = m->mux_buf_sz, 3548c2ecf20Sopenharmony_ci .dest_offset = m->mux_buf_offset, 3558c2ecf20Sopenharmony_ci }; 3568c2ecf20Sopenharmony_ci u32 initial_offset = m->mux_buf_offset; 3578c2ecf20Sopenharmony_ci struct vidtv_mux_pid_ctx *ctx; 3588c2ecf20Sopenharmony_ci u32 nbytes; 3598c2ecf20Sopenharmony_ci u32 i; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci ctx = vidtv_mux_get_pid_ctx(m, TS_NULL_PACKET_PID); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci args.continuity_counter = &ctx->cc; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci for (i = 0; i < npkts; ++i) { 3668c2ecf20Sopenharmony_ci m->mux_buf_offset += vidtv_ts_null_write_into(args); 3678c2ecf20Sopenharmony_ci args.dest_offset = m->mux_buf_offset; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci nbytes = m->mux_buf_offset - initial_offset; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci /* sanity check */ 3738c2ecf20Sopenharmony_ci if (nbytes != npkts * TS_PACKET_LEN) 3748c2ecf20Sopenharmony_ci dev_err_ratelimited(m->dev, "%d != %d\n", 3758c2ecf20Sopenharmony_ci nbytes, npkts * TS_PACKET_LEN); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci return nbytes; 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_cistatic void vidtv_mux_clear(struct vidtv_mux *m) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci /* clear the packets currently in the mux */ 3838c2ecf20Sopenharmony_ci memset(m->mux_buf, 0, m->mux_buf_sz * sizeof(*m->mux_buf)); 3848c2ecf20Sopenharmony_ci /* point to the beginning of the buffer again */ 3858c2ecf20Sopenharmony_ci m->mux_buf_offset = 0; 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci#define ERR_RATE 10000000 3898c2ecf20Sopenharmony_cistatic void vidtv_mux_tick(struct work_struct *work) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci struct vidtv_mux *m = container_of(work, 3928c2ecf20Sopenharmony_ci struct vidtv_mux, 3938c2ecf20Sopenharmony_ci mpeg_thread); 3948c2ecf20Sopenharmony_ci struct dtv_frontend_properties *c = &m->fe->dtv_property_cache; 3958c2ecf20Sopenharmony_ci u32 tot_bits = 0; 3968c2ecf20Sopenharmony_ci u32 nbytes; 3978c2ecf20Sopenharmony_ci u32 npkts; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci while (m->streaming) { 4008c2ecf20Sopenharmony_ci nbytes = 0; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci vidtv_mux_update_clk(m); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci if (vidtv_mux_should_push_pcr(m)) 4058c2ecf20Sopenharmony_ci nbytes += vidtv_mux_push_pcr(m); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci if (vidtv_mux_should_push_si(m)) 4088c2ecf20Sopenharmony_ci nbytes += vidtv_mux_push_si(m); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci nbytes += vidtv_mux_poll_encoders(m); 4118c2ecf20Sopenharmony_ci nbytes += vidtv_mux_pad_with_nulls(m, 256); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci npkts = nbytes / TS_PACKET_LEN; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci /* if the buffer is not aligned there is a bug somewhere */ 4168c2ecf20Sopenharmony_ci if (nbytes % TS_PACKET_LEN) 4178c2ecf20Sopenharmony_ci dev_err_ratelimited(m->dev, "Misaligned buffer\n"); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (m->on_new_packets_available_cb) 4208c2ecf20Sopenharmony_ci m->on_new_packets_available_cb(m->priv, 4218c2ecf20Sopenharmony_ci m->mux_buf, 4228c2ecf20Sopenharmony_ci npkts); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci vidtv_mux_clear(m); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci /* 4278c2ecf20Sopenharmony_ci * Update bytes and packet counts at DVBv5 stats 4288c2ecf20Sopenharmony_ci * 4298c2ecf20Sopenharmony_ci * For now, both pre and post bit counts are identical, 4308c2ecf20Sopenharmony_ci * but post BER count can be lower than pre BER, if the error 4318c2ecf20Sopenharmony_ci * correction logic discards packages. 4328c2ecf20Sopenharmony_ci */ 4338c2ecf20Sopenharmony_ci c->pre_bit_count.stat[0].uvalue = nbytes * 8; 4348c2ecf20Sopenharmony_ci c->post_bit_count.stat[0].uvalue = nbytes * 8; 4358c2ecf20Sopenharmony_ci c->block_count.stat[0].uvalue += npkts; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci /* 4388c2ecf20Sopenharmony_ci * Even without any visible errors for the user, the pre-BER 4398c2ecf20Sopenharmony_ci * stats usually have an error range up to 1E-6. So, 4408c2ecf20Sopenharmony_ci * add some random error increment count to it. 4418c2ecf20Sopenharmony_ci * 4428c2ecf20Sopenharmony_ci * Please notice that this is a poor guy's implementation, 4438c2ecf20Sopenharmony_ci * as it will produce one corrected bit error every time 4448c2ecf20Sopenharmony_ci * ceil(total bytes / ERR_RATE) is incremented, without 4458c2ecf20Sopenharmony_ci * any sort of (pseudo-)randomness. 4468c2ecf20Sopenharmony_ci */ 4478c2ecf20Sopenharmony_ci tot_bits += nbytes * 8; 4488c2ecf20Sopenharmony_ci if (tot_bits > ERR_RATE) { 4498c2ecf20Sopenharmony_ci c->pre_bit_error.stat[0].uvalue++; 4508c2ecf20Sopenharmony_ci tot_bits -= ERR_RATE; 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci usleep_range(VIDTV_SLEEP_USECS, VIDTV_MAX_SLEEP_USECS); 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci} 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_civoid vidtv_mux_start_thread(struct vidtv_mux *m) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci if (m->streaming) { 4608c2ecf20Sopenharmony_ci dev_warn_ratelimited(m->dev, "Already streaming. Skipping.\n"); 4618c2ecf20Sopenharmony_ci return; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci m->streaming = true; 4658c2ecf20Sopenharmony_ci m->timing.start_jiffies = get_jiffies_64(); 4668c2ecf20Sopenharmony_ci schedule_work(&m->mpeg_thread); 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_civoid vidtv_mux_stop_thread(struct vidtv_mux *m) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci if (m->streaming) { 4728c2ecf20Sopenharmony_ci m->streaming = false; /* thread will quit */ 4738c2ecf20Sopenharmony_ci cancel_work_sync(&m->mpeg_thread); 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci} 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_cistruct vidtv_mux *vidtv_mux_init(struct dvb_frontend *fe, 4788c2ecf20Sopenharmony_ci struct device *dev, 4798c2ecf20Sopenharmony_ci struct vidtv_mux_init_args *args) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci struct vidtv_mux *m; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci m = kzalloc(sizeof(*m), GFP_KERNEL); 4848c2ecf20Sopenharmony_ci if (!m) 4858c2ecf20Sopenharmony_ci return NULL; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci m->dev = dev; 4888c2ecf20Sopenharmony_ci m->fe = fe; 4898c2ecf20Sopenharmony_ci m->timing.pcr_period_usecs = args->pcr_period_usecs; 4908c2ecf20Sopenharmony_ci m->timing.si_period_usecs = args->si_period_usecs; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci m->mux_rate_kbytes_sec = args->mux_rate_kbytes_sec; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci m->on_new_packets_available_cb = args->on_new_packets_available_cb; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci m->mux_buf = vzalloc(args->mux_buf_sz); 4978c2ecf20Sopenharmony_ci if (!m->mux_buf) 4988c2ecf20Sopenharmony_ci goto free_mux; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci m->mux_buf_sz = args->mux_buf_sz; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci m->pcr_pid = args->pcr_pid; 5038c2ecf20Sopenharmony_ci m->transport_stream_id = args->transport_stream_id; 5048c2ecf20Sopenharmony_ci m->priv = args->priv; 5058c2ecf20Sopenharmony_ci m->network_id = args->network_id; 5068c2ecf20Sopenharmony_ci m->network_name = kstrdup(args->network_name, GFP_KERNEL); 5078c2ecf20Sopenharmony_ci if (!m->network_name) 5088c2ecf20Sopenharmony_ci goto free_mux_buf; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci m->timing.current_jiffies = get_jiffies_64(); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci if (args->channels) 5138c2ecf20Sopenharmony_ci m->channels = args->channels; 5148c2ecf20Sopenharmony_ci else 5158c2ecf20Sopenharmony_ci if (vidtv_channels_init(m) < 0) 5168c2ecf20Sopenharmony_ci goto free_mux_network_name; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci /* will alloc data for pmt_sections after initializing pat */ 5198c2ecf20Sopenharmony_ci if (vidtv_channel_si_init(m) < 0) 5208c2ecf20Sopenharmony_ci goto free_channels; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci INIT_WORK(&m->mpeg_thread, vidtv_mux_tick); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci if (vidtv_mux_pid_ctx_init(m) < 0) 5258c2ecf20Sopenharmony_ci goto free_channel_si; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci return m; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_cifree_channel_si: 5308c2ecf20Sopenharmony_ci vidtv_channel_si_destroy(m); 5318c2ecf20Sopenharmony_cifree_channels: 5328c2ecf20Sopenharmony_ci vidtv_channels_destroy(m); 5338c2ecf20Sopenharmony_cifree_mux_network_name: 5348c2ecf20Sopenharmony_ci kfree(m->network_name); 5358c2ecf20Sopenharmony_cifree_mux_buf: 5368c2ecf20Sopenharmony_ci vfree(m->mux_buf); 5378c2ecf20Sopenharmony_cifree_mux: 5388c2ecf20Sopenharmony_ci kfree(m); 5398c2ecf20Sopenharmony_ci return NULL; 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_civoid vidtv_mux_destroy(struct vidtv_mux *m) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci vidtv_mux_stop_thread(m); 5458c2ecf20Sopenharmony_ci vidtv_mux_pid_ctx_destroy(m); 5468c2ecf20Sopenharmony_ci vidtv_channel_si_destroy(m); 5478c2ecf20Sopenharmony_ci vidtv_channels_destroy(m); 5488c2ecf20Sopenharmony_ci kfree(m->network_name); 5498c2ecf20Sopenharmony_ci vfree(m->mux_buf); 5508c2ecf20Sopenharmony_ci kfree(m); 5518c2ecf20Sopenharmony_ci} 552