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 multiplexer logic for TS packets from different 862306a36Sopenharmony_ci * elementary streams 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Loosely based on libavcodec/mpegtsenc.c 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Copyright (C) 2020 Daniel W. S. Almeida 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/delay.h> 1662306a36Sopenharmony_ci#include <linux/dev_printk.h> 1762306a36Sopenharmony_ci#include <linux/jiffies.h> 1862306a36Sopenharmony_ci#include <linux/kernel.h> 1962306a36Sopenharmony_ci#include <linux/math64.h> 2062306a36Sopenharmony_ci#include <linux/ratelimit.h> 2162306a36Sopenharmony_ci#include <linux/slab.h> 2262306a36Sopenharmony_ci#include <linux/types.h> 2362306a36Sopenharmony_ci#include <linux/vmalloc.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include "vidtv_channel.h" 2662306a36Sopenharmony_ci#include "vidtv_common.h" 2762306a36Sopenharmony_ci#include "vidtv_encoder.h" 2862306a36Sopenharmony_ci#include "vidtv_mux.h" 2962306a36Sopenharmony_ci#include "vidtv_pes.h" 3062306a36Sopenharmony_ci#include "vidtv_psi.h" 3162306a36Sopenharmony_ci#include "vidtv_ts.h" 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic struct vidtv_mux_pid_ctx 3462306a36Sopenharmony_ci*vidtv_mux_get_pid_ctx(struct vidtv_mux *m, u16 pid) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci struct vidtv_mux_pid_ctx *ctx; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci hash_for_each_possible(m->pid_ctx, ctx, h, pid) 3962306a36Sopenharmony_ci if (ctx->pid == pid) 4062306a36Sopenharmony_ci return ctx; 4162306a36Sopenharmony_ci return NULL; 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic struct vidtv_mux_pid_ctx 4562306a36Sopenharmony_ci*vidtv_mux_create_pid_ctx_once(struct vidtv_mux *m, u16 pid) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci struct vidtv_mux_pid_ctx *ctx; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci ctx = vidtv_mux_get_pid_ctx(m, pid); 5062306a36Sopenharmony_ci if (ctx) 5162306a36Sopenharmony_ci return ctx; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 5462306a36Sopenharmony_ci if (!ctx) 5562306a36Sopenharmony_ci return NULL; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci ctx->pid = pid; 5862306a36Sopenharmony_ci ctx->cc = 0; 5962306a36Sopenharmony_ci hash_add(m->pid_ctx, &ctx->h, pid); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci return ctx; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic void vidtv_mux_pid_ctx_destroy(struct vidtv_mux *m) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci struct vidtv_mux_pid_ctx *ctx; 6762306a36Sopenharmony_ci struct hlist_node *tmp; 6862306a36Sopenharmony_ci int bkt; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci hash_for_each_safe(m->pid_ctx, bkt, tmp, ctx, h) { 7162306a36Sopenharmony_ci hash_del(&ctx->h); 7262306a36Sopenharmony_ci kfree(ctx); 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic int vidtv_mux_pid_ctx_init(struct vidtv_mux *m) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci struct vidtv_psi_table_pat_program *p = m->si.pat->program; 7962306a36Sopenharmony_ci u16 pid; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci hash_init(m->pid_ctx); 8262306a36Sopenharmony_ci /* push the pcr pid ctx */ 8362306a36Sopenharmony_ci if (!vidtv_mux_create_pid_ctx_once(m, m->pcr_pid)) 8462306a36Sopenharmony_ci return -ENOMEM; 8562306a36Sopenharmony_ci /* push the NULL packet pid ctx */ 8662306a36Sopenharmony_ci if (!vidtv_mux_create_pid_ctx_once(m, TS_NULL_PACKET_PID)) 8762306a36Sopenharmony_ci goto free; 8862306a36Sopenharmony_ci /* push the PAT pid ctx */ 8962306a36Sopenharmony_ci if (!vidtv_mux_create_pid_ctx_once(m, VIDTV_PAT_PID)) 9062306a36Sopenharmony_ci goto free; 9162306a36Sopenharmony_ci /* push the SDT pid ctx */ 9262306a36Sopenharmony_ci if (!vidtv_mux_create_pid_ctx_once(m, VIDTV_SDT_PID)) 9362306a36Sopenharmony_ci goto free; 9462306a36Sopenharmony_ci /* push the NIT pid ctx */ 9562306a36Sopenharmony_ci if (!vidtv_mux_create_pid_ctx_once(m, VIDTV_NIT_PID)) 9662306a36Sopenharmony_ci goto free; 9762306a36Sopenharmony_ci /* push the EIT pid ctx */ 9862306a36Sopenharmony_ci if (!vidtv_mux_create_pid_ctx_once(m, VIDTV_EIT_PID)) 9962306a36Sopenharmony_ci goto free; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /* add a ctx for all PMT sections */ 10262306a36Sopenharmony_ci while (p) { 10362306a36Sopenharmony_ci pid = vidtv_psi_get_pat_program_pid(p); 10462306a36Sopenharmony_ci vidtv_mux_create_pid_ctx_once(m, pid); 10562306a36Sopenharmony_ci p = p->next; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci return 0; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cifree: 11162306a36Sopenharmony_ci vidtv_mux_pid_ctx_destroy(m); 11262306a36Sopenharmony_ci return -ENOMEM; 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic void vidtv_mux_update_clk(struct vidtv_mux *m) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci /* call this at every thread iteration */ 11862306a36Sopenharmony_ci u64 elapsed_time; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci m->timing.past_jiffies = m->timing.current_jiffies; 12162306a36Sopenharmony_ci m->timing.current_jiffies = get_jiffies_64(); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci elapsed_time = jiffies_to_usecs(m->timing.current_jiffies - 12462306a36Sopenharmony_ci m->timing.past_jiffies); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci /* update the 27Mhz clock proportionally to the elapsed time */ 12762306a36Sopenharmony_ci m->timing.clk += (CLOCK_UNIT_27MHZ / USEC_PER_SEC) * elapsed_time; 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic u32 vidtv_mux_push_si(struct vidtv_mux *m) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci struct vidtv_psi_pat_write_args pat_args = { 13362306a36Sopenharmony_ci .buf = m->mux_buf, 13462306a36Sopenharmony_ci .buf_sz = m->mux_buf_sz, 13562306a36Sopenharmony_ci .pat = m->si.pat, 13662306a36Sopenharmony_ci }; 13762306a36Sopenharmony_ci struct vidtv_psi_pmt_write_args pmt_args = { 13862306a36Sopenharmony_ci .buf = m->mux_buf, 13962306a36Sopenharmony_ci .buf_sz = m->mux_buf_sz, 14062306a36Sopenharmony_ci .pcr_pid = m->pcr_pid, 14162306a36Sopenharmony_ci }; 14262306a36Sopenharmony_ci struct vidtv_psi_sdt_write_args sdt_args = { 14362306a36Sopenharmony_ci .buf = m->mux_buf, 14462306a36Sopenharmony_ci .buf_sz = m->mux_buf_sz, 14562306a36Sopenharmony_ci .sdt = m->si.sdt, 14662306a36Sopenharmony_ci }; 14762306a36Sopenharmony_ci struct vidtv_psi_nit_write_args nit_args = { 14862306a36Sopenharmony_ci .buf = m->mux_buf, 14962306a36Sopenharmony_ci .buf_sz = m->mux_buf_sz, 15062306a36Sopenharmony_ci .nit = m->si.nit, 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci }; 15362306a36Sopenharmony_ci struct vidtv_psi_eit_write_args eit_args = { 15462306a36Sopenharmony_ci .buf = m->mux_buf, 15562306a36Sopenharmony_ci .buf_sz = m->mux_buf_sz, 15662306a36Sopenharmony_ci .eit = m->si.eit, 15762306a36Sopenharmony_ci }; 15862306a36Sopenharmony_ci u32 initial_offset = m->mux_buf_offset; 15962306a36Sopenharmony_ci struct vidtv_mux_pid_ctx *pat_ctx; 16062306a36Sopenharmony_ci struct vidtv_mux_pid_ctx *pmt_ctx; 16162306a36Sopenharmony_ci struct vidtv_mux_pid_ctx *sdt_ctx; 16262306a36Sopenharmony_ci struct vidtv_mux_pid_ctx *nit_ctx; 16362306a36Sopenharmony_ci struct vidtv_mux_pid_ctx *eit_ctx; 16462306a36Sopenharmony_ci u32 nbytes; 16562306a36Sopenharmony_ci u16 pmt_pid; 16662306a36Sopenharmony_ci u32 i; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci pat_ctx = vidtv_mux_get_pid_ctx(m, VIDTV_PAT_PID); 16962306a36Sopenharmony_ci sdt_ctx = vidtv_mux_get_pid_ctx(m, VIDTV_SDT_PID); 17062306a36Sopenharmony_ci nit_ctx = vidtv_mux_get_pid_ctx(m, VIDTV_NIT_PID); 17162306a36Sopenharmony_ci eit_ctx = vidtv_mux_get_pid_ctx(m, VIDTV_EIT_PID); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci pat_args.offset = m->mux_buf_offset; 17462306a36Sopenharmony_ci pat_args.continuity_counter = &pat_ctx->cc; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci m->mux_buf_offset += vidtv_psi_pat_write_into(&pat_args); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci for (i = 0; i < m->si.pat->num_pmt; ++i) { 17962306a36Sopenharmony_ci pmt_pid = vidtv_psi_pmt_get_pid(m->si.pmt_secs[i], 18062306a36Sopenharmony_ci m->si.pat); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if (pmt_pid > TS_LAST_VALID_PID) { 18362306a36Sopenharmony_ci dev_warn_ratelimited(m->dev, 18462306a36Sopenharmony_ci "PID: %d not found\n", pmt_pid); 18562306a36Sopenharmony_ci continue; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci pmt_ctx = vidtv_mux_get_pid_ctx(m, pmt_pid); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci pmt_args.offset = m->mux_buf_offset; 19162306a36Sopenharmony_ci pmt_args.pmt = m->si.pmt_secs[i]; 19262306a36Sopenharmony_ci pmt_args.pid = pmt_pid; 19362306a36Sopenharmony_ci pmt_args.continuity_counter = &pmt_ctx->cc; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci /* write each section into buffer */ 19662306a36Sopenharmony_ci m->mux_buf_offset += vidtv_psi_pmt_write_into(&pmt_args); 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci sdt_args.offset = m->mux_buf_offset; 20062306a36Sopenharmony_ci sdt_args.continuity_counter = &sdt_ctx->cc; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci m->mux_buf_offset += vidtv_psi_sdt_write_into(&sdt_args); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci nit_args.offset = m->mux_buf_offset; 20562306a36Sopenharmony_ci nit_args.continuity_counter = &nit_ctx->cc; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci m->mux_buf_offset += vidtv_psi_nit_write_into(&nit_args); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci eit_args.offset = m->mux_buf_offset; 21062306a36Sopenharmony_ci eit_args.continuity_counter = &eit_ctx->cc; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci m->mux_buf_offset += vidtv_psi_eit_write_into(&eit_args); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci nbytes = m->mux_buf_offset - initial_offset; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci m->num_streamed_si++; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci return nbytes; 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic u32 vidtv_mux_push_pcr(struct vidtv_mux *m) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci struct pcr_write_args args = {}; 22462306a36Sopenharmony_ci struct vidtv_mux_pid_ctx *ctx; 22562306a36Sopenharmony_ci u32 nbytes = 0; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci ctx = vidtv_mux_get_pid_ctx(m, m->pcr_pid); 22862306a36Sopenharmony_ci args.dest_buf = m->mux_buf; 22962306a36Sopenharmony_ci args.pid = m->pcr_pid; 23062306a36Sopenharmony_ci args.buf_sz = m->mux_buf_sz; 23162306a36Sopenharmony_ci args.continuity_counter = &ctx->cc; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci /* the 27Mhz clock will feed both parts of the PCR bitfield */ 23462306a36Sopenharmony_ci args.pcr = m->timing.clk; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci nbytes += vidtv_ts_pcr_write_into(args); 23762306a36Sopenharmony_ci m->mux_buf_offset += nbytes; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci m->num_streamed_pcr++; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci return nbytes; 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic bool vidtv_mux_should_push_pcr(struct vidtv_mux *m) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci u64 next_pcr_at; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci if (m->num_streamed_pcr == 0) 24962306a36Sopenharmony_ci return true; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci next_pcr_at = m->timing.start_jiffies + 25262306a36Sopenharmony_ci usecs_to_jiffies(m->num_streamed_pcr * 25362306a36Sopenharmony_ci m->timing.pcr_period_usecs); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci return time_after64(m->timing.current_jiffies, next_pcr_at); 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic bool vidtv_mux_should_push_si(struct vidtv_mux *m) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci u64 next_si_at; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci if (m->num_streamed_si == 0) 26362306a36Sopenharmony_ci return true; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci next_si_at = m->timing.start_jiffies + 26662306a36Sopenharmony_ci usecs_to_jiffies(m->num_streamed_si * 26762306a36Sopenharmony_ci m->timing.si_period_usecs); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci return time_after64(m->timing.current_jiffies, next_si_at); 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic u32 vidtv_mux_packetize_access_units(struct vidtv_mux *m, 27362306a36Sopenharmony_ci struct vidtv_encoder *e) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci struct pes_write_args args = { 27662306a36Sopenharmony_ci .dest_buf = m->mux_buf, 27762306a36Sopenharmony_ci .dest_buf_sz = m->mux_buf_sz, 27862306a36Sopenharmony_ci .pid = be16_to_cpu(e->es_pid), 27962306a36Sopenharmony_ci .encoder_id = e->id, 28062306a36Sopenharmony_ci .stream_id = be16_to_cpu(e->stream_id), 28162306a36Sopenharmony_ci .send_pts = true, /* forbidden value '01'... */ 28262306a36Sopenharmony_ci .send_dts = false, /* ...for PTS_DTS flags */ 28362306a36Sopenharmony_ci }; 28462306a36Sopenharmony_ci struct vidtv_access_unit *au = e->access_units; 28562306a36Sopenharmony_ci u32 initial_offset = m->mux_buf_offset; 28662306a36Sopenharmony_ci struct vidtv_mux_pid_ctx *pid_ctx; 28762306a36Sopenharmony_ci u32 nbytes = 0; 28862306a36Sopenharmony_ci u8 *buf = NULL; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci /* see SMPTE 302M clause 6.4 */ 29162306a36Sopenharmony_ci if (args.encoder_id == S302M) { 29262306a36Sopenharmony_ci args.send_dts = false; 29362306a36Sopenharmony_ci args.send_pts = true; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci pid_ctx = vidtv_mux_create_pid_ctx_once(m, be16_to_cpu(e->es_pid)); 29762306a36Sopenharmony_ci args.continuity_counter = &pid_ctx->cc; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci while (au) { 30062306a36Sopenharmony_ci buf = e->encoder_buf + au->offset; 30162306a36Sopenharmony_ci args.from = buf; 30262306a36Sopenharmony_ci args.access_unit_len = au->nbytes; 30362306a36Sopenharmony_ci args.dest_offset = m->mux_buf_offset; 30462306a36Sopenharmony_ci args.pts = au->pts; 30562306a36Sopenharmony_ci args.pcr = m->timing.clk; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci m->mux_buf_offset += vidtv_pes_write_into(&args); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci au = au->next; 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci /* 31362306a36Sopenharmony_ci * clear the encoder state once the ES data has been written to the mux 31462306a36Sopenharmony_ci * buffer 31562306a36Sopenharmony_ci */ 31662306a36Sopenharmony_ci e->clear(e); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci nbytes = m->mux_buf_offset - initial_offset; 31962306a36Sopenharmony_ci return nbytes; 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_cistatic u32 vidtv_mux_poll_encoders(struct vidtv_mux *m) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci struct vidtv_channel *cur_chnl = m->channels; 32562306a36Sopenharmony_ci struct vidtv_encoder *e = NULL; 32662306a36Sopenharmony_ci u32 nbytes = 0; 32762306a36Sopenharmony_ci u32 au_nbytes; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci while (cur_chnl) { 33062306a36Sopenharmony_ci e = cur_chnl->encoders; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci while (e) { 33362306a36Sopenharmony_ci e->encode(e); 33462306a36Sopenharmony_ci /* get the TS packets into the mux buffer */ 33562306a36Sopenharmony_ci au_nbytes = vidtv_mux_packetize_access_units(m, e); 33662306a36Sopenharmony_ci nbytes += au_nbytes; 33762306a36Sopenharmony_ci m->mux_buf_offset += au_nbytes; 33862306a36Sopenharmony_ci /* grab next encoder */ 33962306a36Sopenharmony_ci e = e->next; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci /* grab the next channel */ 34362306a36Sopenharmony_ci cur_chnl = cur_chnl->next; 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci return nbytes; 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic u32 vidtv_mux_pad_with_nulls(struct vidtv_mux *m, u32 npkts) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci struct null_packet_write_args args = { 35262306a36Sopenharmony_ci .dest_buf = m->mux_buf, 35362306a36Sopenharmony_ci .buf_sz = m->mux_buf_sz, 35462306a36Sopenharmony_ci .dest_offset = m->mux_buf_offset, 35562306a36Sopenharmony_ci }; 35662306a36Sopenharmony_ci u32 initial_offset = m->mux_buf_offset; 35762306a36Sopenharmony_ci struct vidtv_mux_pid_ctx *ctx; 35862306a36Sopenharmony_ci u32 nbytes; 35962306a36Sopenharmony_ci u32 i; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci ctx = vidtv_mux_get_pid_ctx(m, TS_NULL_PACKET_PID); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci args.continuity_counter = &ctx->cc; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci for (i = 0; i < npkts; ++i) { 36662306a36Sopenharmony_ci m->mux_buf_offset += vidtv_ts_null_write_into(args); 36762306a36Sopenharmony_ci args.dest_offset = m->mux_buf_offset; 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci nbytes = m->mux_buf_offset - initial_offset; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci /* sanity check */ 37362306a36Sopenharmony_ci if (nbytes != npkts * TS_PACKET_LEN) 37462306a36Sopenharmony_ci dev_err_ratelimited(m->dev, "%d != %d\n", 37562306a36Sopenharmony_ci nbytes, npkts * TS_PACKET_LEN); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci return nbytes; 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic void vidtv_mux_clear(struct vidtv_mux *m) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci /* clear the packets currently in the mux */ 38362306a36Sopenharmony_ci memset(m->mux_buf, 0, m->mux_buf_sz * sizeof(*m->mux_buf)); 38462306a36Sopenharmony_ci /* point to the beginning of the buffer again */ 38562306a36Sopenharmony_ci m->mux_buf_offset = 0; 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci#define ERR_RATE 10000000 38962306a36Sopenharmony_cistatic void vidtv_mux_tick(struct work_struct *work) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci struct vidtv_mux *m = container_of(work, 39262306a36Sopenharmony_ci struct vidtv_mux, 39362306a36Sopenharmony_ci mpeg_thread); 39462306a36Sopenharmony_ci struct dtv_frontend_properties *c = &m->fe->dtv_property_cache; 39562306a36Sopenharmony_ci u32 tot_bits = 0; 39662306a36Sopenharmony_ci u32 nbytes; 39762306a36Sopenharmony_ci u32 npkts; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci while (m->streaming) { 40062306a36Sopenharmony_ci nbytes = 0; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci vidtv_mux_update_clk(m); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (vidtv_mux_should_push_pcr(m)) 40562306a36Sopenharmony_ci nbytes += vidtv_mux_push_pcr(m); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci if (vidtv_mux_should_push_si(m)) 40862306a36Sopenharmony_ci nbytes += vidtv_mux_push_si(m); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci nbytes += vidtv_mux_poll_encoders(m); 41162306a36Sopenharmony_ci nbytes += vidtv_mux_pad_with_nulls(m, 256); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci npkts = nbytes / TS_PACKET_LEN; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci /* if the buffer is not aligned there is a bug somewhere */ 41662306a36Sopenharmony_ci if (nbytes % TS_PACKET_LEN) 41762306a36Sopenharmony_ci dev_err_ratelimited(m->dev, "Misaligned buffer\n"); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (m->on_new_packets_available_cb) 42062306a36Sopenharmony_ci m->on_new_packets_available_cb(m->priv, 42162306a36Sopenharmony_ci m->mux_buf, 42262306a36Sopenharmony_ci npkts); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci vidtv_mux_clear(m); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci /* 42762306a36Sopenharmony_ci * Update bytes and packet counts at DVBv5 stats 42862306a36Sopenharmony_ci * 42962306a36Sopenharmony_ci * For now, both pre and post bit counts are identical, 43062306a36Sopenharmony_ci * but post BER count can be lower than pre BER, if the error 43162306a36Sopenharmony_ci * correction logic discards packages. 43262306a36Sopenharmony_ci */ 43362306a36Sopenharmony_ci c->pre_bit_count.stat[0].uvalue = nbytes * 8; 43462306a36Sopenharmony_ci c->post_bit_count.stat[0].uvalue = nbytes * 8; 43562306a36Sopenharmony_ci c->block_count.stat[0].uvalue += npkts; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci /* 43862306a36Sopenharmony_ci * Even without any visible errors for the user, the pre-BER 43962306a36Sopenharmony_ci * stats usually have an error range up to 1E-6. So, 44062306a36Sopenharmony_ci * add some random error increment count to it. 44162306a36Sopenharmony_ci * 44262306a36Sopenharmony_ci * Please notice that this is a poor guy's implementation, 44362306a36Sopenharmony_ci * as it will produce one corrected bit error every time 44462306a36Sopenharmony_ci * ceil(total bytes / ERR_RATE) is incremented, without 44562306a36Sopenharmony_ci * any sort of (pseudo-)randomness. 44662306a36Sopenharmony_ci */ 44762306a36Sopenharmony_ci tot_bits += nbytes * 8; 44862306a36Sopenharmony_ci if (tot_bits > ERR_RATE) { 44962306a36Sopenharmony_ci c->pre_bit_error.stat[0].uvalue++; 45062306a36Sopenharmony_ci tot_bits -= ERR_RATE; 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci usleep_range(VIDTV_SLEEP_USECS, VIDTV_MAX_SLEEP_USECS); 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_civoid vidtv_mux_start_thread(struct vidtv_mux *m) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci if (m->streaming) { 46062306a36Sopenharmony_ci dev_warn_ratelimited(m->dev, "Already streaming. Skipping.\n"); 46162306a36Sopenharmony_ci return; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci m->streaming = true; 46562306a36Sopenharmony_ci m->timing.start_jiffies = get_jiffies_64(); 46662306a36Sopenharmony_ci schedule_work(&m->mpeg_thread); 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_civoid vidtv_mux_stop_thread(struct vidtv_mux *m) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci if (m->streaming) { 47262306a36Sopenharmony_ci m->streaming = false; /* thread will quit */ 47362306a36Sopenharmony_ci cancel_work_sync(&m->mpeg_thread); 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistruct vidtv_mux *vidtv_mux_init(struct dvb_frontend *fe, 47862306a36Sopenharmony_ci struct device *dev, 47962306a36Sopenharmony_ci struct vidtv_mux_init_args *args) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci struct vidtv_mux *m; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci m = kzalloc(sizeof(*m), GFP_KERNEL); 48462306a36Sopenharmony_ci if (!m) 48562306a36Sopenharmony_ci return NULL; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci m->dev = dev; 48862306a36Sopenharmony_ci m->fe = fe; 48962306a36Sopenharmony_ci m->timing.pcr_period_usecs = args->pcr_period_usecs; 49062306a36Sopenharmony_ci m->timing.si_period_usecs = args->si_period_usecs; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci m->mux_rate_kbytes_sec = args->mux_rate_kbytes_sec; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci m->on_new_packets_available_cb = args->on_new_packets_available_cb; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci m->mux_buf = vzalloc(args->mux_buf_sz); 49762306a36Sopenharmony_ci if (!m->mux_buf) 49862306a36Sopenharmony_ci goto free_mux; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci m->mux_buf_sz = args->mux_buf_sz; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci m->pcr_pid = args->pcr_pid; 50362306a36Sopenharmony_ci m->transport_stream_id = args->transport_stream_id; 50462306a36Sopenharmony_ci m->priv = args->priv; 50562306a36Sopenharmony_ci m->network_id = args->network_id; 50662306a36Sopenharmony_ci m->network_name = kstrdup(args->network_name, GFP_KERNEL); 50762306a36Sopenharmony_ci if (!m->network_name) 50862306a36Sopenharmony_ci goto free_mux_buf; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci m->timing.current_jiffies = get_jiffies_64(); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci if (args->channels) 51362306a36Sopenharmony_ci m->channels = args->channels; 51462306a36Sopenharmony_ci else 51562306a36Sopenharmony_ci if (vidtv_channels_init(m) < 0) 51662306a36Sopenharmony_ci goto free_mux_network_name; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci /* will alloc data for pmt_sections after initializing pat */ 51962306a36Sopenharmony_ci if (vidtv_channel_si_init(m) < 0) 52062306a36Sopenharmony_ci goto free_channels; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci INIT_WORK(&m->mpeg_thread, vidtv_mux_tick); 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci if (vidtv_mux_pid_ctx_init(m) < 0) 52562306a36Sopenharmony_ci goto free_channel_si; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci return m; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_cifree_channel_si: 53062306a36Sopenharmony_ci vidtv_channel_si_destroy(m); 53162306a36Sopenharmony_cifree_channels: 53262306a36Sopenharmony_ci vidtv_channels_destroy(m); 53362306a36Sopenharmony_cifree_mux_network_name: 53462306a36Sopenharmony_ci kfree(m->network_name); 53562306a36Sopenharmony_cifree_mux_buf: 53662306a36Sopenharmony_ci vfree(m->mux_buf); 53762306a36Sopenharmony_cifree_mux: 53862306a36Sopenharmony_ci kfree(m); 53962306a36Sopenharmony_ci return NULL; 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_civoid vidtv_mux_destroy(struct vidtv_mux *m) 54362306a36Sopenharmony_ci{ 54462306a36Sopenharmony_ci vidtv_mux_stop_thread(m); 54562306a36Sopenharmony_ci vidtv_mux_pid_ctx_destroy(m); 54662306a36Sopenharmony_ci vidtv_channel_si_destroy(m); 54762306a36Sopenharmony_ci vidtv_channels_destroy(m); 54862306a36Sopenharmony_ci kfree(m->network_name); 54962306a36Sopenharmony_ci vfree(m->mux_buf); 55062306a36Sopenharmony_ci kfree(m); 55162306a36Sopenharmony_ci} 552