diff options
Diffstat (limited to 'drivers/media/test-drivers/vidtv/vidtv_mux.c')
-rw-r--r-- | drivers/media/test-drivers/vidtv/vidtv_mux.c | 248 |
1 files changed, 160 insertions, 88 deletions
diff --git a/drivers/media/test-drivers/vidtv/vidtv_mux.c b/drivers/media/test-drivers/vidtv/vidtv_mux.c index 082740ae9d44..b51e6a3b8cbe 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_mux.c +++ b/drivers/media/test-drivers/vidtv/vidtv_mux.c @@ -12,23 +12,23 @@ * Copyright (C) 2020 Daniel W. S. Almeida */ -#include <linux/types.h> -#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/dev_printk.h> #include <linux/jiffies.h> #include <linux/kernel.h> -#include <linux/dev_printk.h> +#include <linux/math64.h> #include <linux/ratelimit.h> -#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/types.h> #include <linux/vmalloc.h> -#include <linux/math64.h> -#include "vidtv_mux.h" -#include "vidtv_ts.h" -#include "vidtv_pes.h" -#include "vidtv_encoder.h" #include "vidtv_channel.h" #include "vidtv_common.h" +#include "vidtv_encoder.h" +#include "vidtv_mux.h" +#include "vidtv_pes.h" #include "vidtv_psi.h" +#include "vidtv_ts.h" static struct vidtv_mux_pid_ctx *vidtv_mux_get_pid_ctx(struct vidtv_mux *m, u16 pid) @@ -47,33 +47,56 @@ static struct vidtv_mux_pid_ctx struct vidtv_mux_pid_ctx *ctx; ctx = vidtv_mux_get_pid_ctx(m, pid); - if (ctx) - goto end; + return ctx; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return NULL; - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); ctx->pid = pid; ctx->cc = 0; hash_add(m->pid_ctx, &ctx->h, pid); -end: return ctx; } -static void vidtv_mux_pid_ctx_init(struct vidtv_mux *m) +static void vidtv_mux_pid_ctx_destroy(struct vidtv_mux *m) +{ + struct vidtv_mux_pid_ctx *ctx; + struct hlist_node *tmp; + int bkt; + + hash_for_each_safe(m->pid_ctx, bkt, tmp, ctx, h) { + hash_del(&ctx->h); + kfree(ctx); + } +} + +static int vidtv_mux_pid_ctx_init(struct vidtv_mux *m) { struct vidtv_psi_table_pat_program *p = m->si.pat->program; u16 pid; hash_init(m->pid_ctx); /* push the pcr pid ctx */ - vidtv_mux_create_pid_ctx_once(m, m->pcr_pid); - /* push the null packet pid ctx */ - vidtv_mux_create_pid_ctx_once(m, TS_NULL_PACKET_PID); + if (!vidtv_mux_create_pid_ctx_once(m, m->pcr_pid)) + return -ENOMEM; + /* push the NULL packet pid ctx */ + if (!vidtv_mux_create_pid_ctx_once(m, TS_NULL_PACKET_PID)) + goto free; /* push the PAT pid ctx */ - vidtv_mux_create_pid_ctx_once(m, VIDTV_PAT_PID); + if (!vidtv_mux_create_pid_ctx_once(m, VIDTV_PAT_PID)) + goto free; /* push the SDT pid ctx */ - vidtv_mux_create_pid_ctx_once(m, VIDTV_SDT_PID); + if (!vidtv_mux_create_pid_ctx_once(m, VIDTV_SDT_PID)) + goto free; + /* push the NIT pid ctx */ + if (!vidtv_mux_create_pid_ctx_once(m, VIDTV_NIT_PID)) + goto free; + /* push the EIT pid ctx */ + if (!vidtv_mux_create_pid_ctx_once(m, VIDTV_EIT_PID)) + goto free; /* add a ctx for all PMT sections */ while (p) { @@ -81,18 +104,12 @@ static void vidtv_mux_pid_ctx_init(struct vidtv_mux *m) vidtv_mux_create_pid_ctx_once(m, pid); p = p->next; } -} -static void vidtv_mux_pid_ctx_destroy(struct vidtv_mux *m) -{ - int bkt; - struct vidtv_mux_pid_ctx *ctx; - struct hlist_node *tmp; + return 0; - hash_for_each_safe(m->pid_ctx, bkt, tmp, ctx, h) { - hash_del(&ctx->h); - kfree(ctx); - } +free: + vidtv_mux_pid_ctx_destroy(m); + return -ENOMEM; } static void vidtv_mux_update_clk(struct vidtv_mux *m) @@ -112,32 +129,53 @@ static void vidtv_mux_update_clk(struct vidtv_mux *m) static u32 vidtv_mux_push_si(struct vidtv_mux *m) { + struct vidtv_psi_pat_write_args pat_args = { + .buf = m->mux_buf, + .buf_sz = m->mux_buf_sz, + .pat = m->si.pat, + }; + struct vidtv_psi_pmt_write_args pmt_args = { + .buf = m->mux_buf, + .buf_sz = m->mux_buf_sz, + .pcr_pid = m->pcr_pid, + }; + struct vidtv_psi_sdt_write_args sdt_args = { + .buf = m->mux_buf, + .buf_sz = m->mux_buf_sz, + .sdt = m->si.sdt, + }; + struct vidtv_psi_nit_write_args nit_args = { + .buf = m->mux_buf, + .buf_sz = m->mux_buf_sz, + .nit = m->si.nit, + + }; + struct vidtv_psi_eit_write_args eit_args = { + .buf = m->mux_buf, + .buf_sz = m->mux_buf_sz, + .eit = m->si.eit, + }; u32 initial_offset = m->mux_buf_offset; - struct vidtv_mux_pid_ctx *pat_ctx; struct vidtv_mux_pid_ctx *pmt_ctx; struct vidtv_mux_pid_ctx *sdt_ctx; - - struct vidtv_psi_pat_write_args pat_args = {}; - struct vidtv_psi_pmt_write_args pmt_args = {}; - struct vidtv_psi_sdt_write_args sdt_args = {}; - - u32 nbytes; /* the number of bytes written by this function */ + struct vidtv_mux_pid_ctx *nit_ctx; + struct vidtv_mux_pid_ctx *eit_ctx; + u32 nbytes; u16 pmt_pid; u32 i; pat_ctx = vidtv_mux_get_pid_ctx(m, VIDTV_PAT_PID); sdt_ctx = vidtv_mux_get_pid_ctx(m, VIDTV_SDT_PID); + nit_ctx = vidtv_mux_get_pid_ctx(m, VIDTV_NIT_PID); + eit_ctx = vidtv_mux_get_pid_ctx(m, VIDTV_EIT_PID); - pat_args.buf = m->mux_buf; pat_args.offset = m->mux_buf_offset; - pat_args.pat = m->si.pat; - pat_args.buf_sz = m->mux_buf_sz; pat_args.continuity_counter = &pat_ctx->cc; - m->mux_buf_offset += vidtv_psi_pat_write_into(pat_args); + m->mux_buf_offset += vidtv_psi_pat_write_into(&pat_args); - for (i = 0; i < m->si.pat->programs; ++i) { + for (i = 0; i < m->si.pat->num_pmt; ++i) { pmt_pid = vidtv_psi_pmt_get_pid(m->si.pmt_secs[i], m->si.pat); @@ -149,25 +187,29 @@ static u32 vidtv_mux_push_si(struct vidtv_mux *m) pmt_ctx = vidtv_mux_get_pid_ctx(m, pmt_pid); - pmt_args.buf = m->mux_buf; pmt_args.offset = m->mux_buf_offset; pmt_args.pmt = m->si.pmt_secs[i]; pmt_args.pid = pmt_pid; - pmt_args.buf_sz = m->mux_buf_sz; pmt_args.continuity_counter = &pmt_ctx->cc; - pmt_args.pcr_pid = m->pcr_pid; /* write each section into buffer */ - m->mux_buf_offset += vidtv_psi_pmt_write_into(pmt_args); + m->mux_buf_offset += vidtv_psi_pmt_write_into(&pmt_args); } - sdt_args.buf = m->mux_buf; sdt_args.offset = m->mux_buf_offset; - sdt_args.sdt = m->si.sdt; - sdt_args.buf_sz = m->mux_buf_sz; sdt_args.continuity_counter = &sdt_ctx->cc; - m->mux_buf_offset += vidtv_psi_sdt_write_into(sdt_args); + m->mux_buf_offset += vidtv_psi_sdt_write_into(&sdt_args); + + nit_args.offset = m->mux_buf_offset; + nit_args.continuity_counter = &nit_ctx->cc; + + m->mux_buf_offset += vidtv_psi_nit_write_into(&nit_args); + + eit_args.offset = m->mux_buf_offset; + eit_args.continuity_counter = &eit_ctx->cc; + + m->mux_buf_offset += vidtv_psi_eit_write_into(&eit_args); nbytes = m->mux_buf_offset - initial_offset; @@ -230,23 +272,29 @@ static bool vidtv_mux_should_push_si(struct vidtv_mux *m) static u32 vidtv_mux_packetize_access_units(struct vidtv_mux *m, struct vidtv_encoder *e) { - u32 nbytes = 0; - - struct pes_write_args args = {}; - u32 initial_offset = m->mux_buf_offset; + struct pes_write_args args = { + .dest_buf = m->mux_buf, + .dest_buf_sz = m->mux_buf_sz, + .pid = be16_to_cpu(e->es_pid), + .encoder_id = e->id, + .stream_id = be16_to_cpu(e->stream_id), + .send_pts = true, /* forbidden value '01'... */ + .send_dts = false, /* ...for PTS_DTS flags */ + }; struct vidtv_access_unit *au = e->access_units; - + u32 initial_offset = m->mux_buf_offset; + struct vidtv_mux_pid_ctx *pid_ctx; + u32 nbytes = 0; u8 *buf = NULL; - struct vidtv_mux_pid_ctx *pid_ctx = vidtv_mux_create_pid_ctx_once(m, - be16_to_cpu(e->es_pid)); - args.dest_buf = m->mux_buf; - args.dest_buf_sz = m->mux_buf_sz; - args.pid = be16_to_cpu(e->es_pid); - args.encoder_id = e->id; + /* see SMPTE 302M clause 6.4 */ + if (args.encoder_id == S302M) { + args.send_dts = false; + args.send_pts = true; + } + + pid_ctx = vidtv_mux_create_pid_ctx_once(m, be16_to_cpu(e->es_pid)); args.continuity_counter = &pid_ctx->cc; - args.stream_id = be16_to_cpu(e->stream_id); - args.send_pts = true; while (au) { buf = e->encoder_buf + au->offset; @@ -256,7 +304,7 @@ static u32 vidtv_mux_packetize_access_units(struct vidtv_mux *m, args.pts = au->pts; args.pcr = m->timing.clk; - m->mux_buf_offset += vidtv_pes_write_into(args); + m->mux_buf_offset += vidtv_pes_write_into(&args); au = au->next; } @@ -273,10 +321,10 @@ static u32 vidtv_mux_packetize_access_units(struct vidtv_mux *m, static u32 vidtv_mux_poll_encoders(struct vidtv_mux *m) { - u32 nbytes = 0; - u32 au_nbytes; struct vidtv_channel *cur_chnl = m->channels; struct vidtv_encoder *e = NULL; + u32 nbytes = 0; + u32 au_nbytes; while (cur_chnl) { e = cur_chnl->encoders; @@ -300,18 +348,19 @@ static u32 vidtv_mux_poll_encoders(struct vidtv_mux *m) static u32 vidtv_mux_pad_with_nulls(struct vidtv_mux *m, u32 npkts) { - struct null_packet_write_args args = {}; + struct null_packet_write_args args = { + .dest_buf = m->mux_buf, + .buf_sz = m->mux_buf_sz, + .dest_offset = m->mux_buf_offset, + }; u32 initial_offset = m->mux_buf_offset; - u32 nbytes; /* the number of bytes written by this function */ - u32 i; struct vidtv_mux_pid_ctx *ctx; + u32 nbytes; + u32 i; ctx = vidtv_mux_get_pid_ctx(m, TS_NULL_PACKET_PID); - args.dest_buf = m->mux_buf; - args.buf_sz = m->mux_buf_sz; args.continuity_counter = &ctx->cc; - args.dest_offset = m->mux_buf_offset; for (i = 0; i < npkts; ++i) { m->mux_buf_offset += vidtv_ts_null_write_into(args); @@ -343,9 +392,9 @@ static void vidtv_mux_tick(struct work_struct *work) struct vidtv_mux, mpeg_thread); struct dtv_frontend_properties *c = &m->fe->dtv_property_cache; + u32 tot_bits = 0; u32 nbytes; u32 npkts; - u32 tot_bits = 0; while (m->streaming) { nbytes = 0; @@ -427,40 +476,62 @@ void vidtv_mux_stop_thread(struct vidtv_mux *m) struct vidtv_mux *vidtv_mux_init(struct dvb_frontend *fe, struct device *dev, - struct vidtv_mux_init_args args) + struct vidtv_mux_init_args *args) { - struct vidtv_mux *m = kzalloc(sizeof(*m), GFP_KERNEL); + struct vidtv_mux *m; + + m = kzalloc(sizeof(*m), GFP_KERNEL); + if (!m) + return NULL; m->dev = dev; m->fe = fe; - m->timing.pcr_period_usecs = args.pcr_period_usecs; - m->timing.si_period_usecs = args.si_period_usecs; + m->timing.pcr_period_usecs = args->pcr_period_usecs; + m->timing.si_period_usecs = args->si_period_usecs; + + m->mux_rate_kbytes_sec = args->mux_rate_kbytes_sec; - m->mux_rate_kbytes_sec = args.mux_rate_kbytes_sec; + m->on_new_packets_available_cb = args->on_new_packets_available_cb; - m->on_new_packets_available_cb = args.on_new_packets_available_cb; + m->mux_buf = vzalloc(args->mux_buf_sz); + if (!m->mux_buf) + goto free_mux; - m->mux_buf = vzalloc(args.mux_buf_sz); - m->mux_buf_sz = args.mux_buf_sz; + m->mux_buf_sz = args->mux_buf_sz; - m->pcr_pid = args.pcr_pid; - m->transport_stream_id = args.transport_stream_id; - m->priv = args.priv; + m->pcr_pid = args->pcr_pid; + m->transport_stream_id = args->transport_stream_id; + m->priv = args->priv; + m->network_id = args->network_id; + m->network_name = kstrdup(args->network_name, GFP_KERNEL); m->timing.current_jiffies = get_jiffies_64(); - if (args.channels) - m->channels = args.channels; + if (args->channels) + m->channels = args->channels; else - vidtv_channels_init(m); + if (vidtv_channels_init(m) < 0) + goto free_mux_buf; /* will alloc data for pmt_sections after initializing pat */ - vidtv_channel_si_init(m); + if (vidtv_channel_si_init(m) < 0) + goto free_channels; INIT_WORK(&m->mpeg_thread, vidtv_mux_tick); - vidtv_mux_pid_ctx_init(m); + if (vidtv_mux_pid_ctx_init(m) < 0) + goto free_channel_si; return m; + +free_channel_si: + vidtv_channel_si_destroy(m); +free_channels: + vidtv_channels_destroy(m); +free_mux_buf: + vfree(m->mux_buf); +free_mux: + kfree(m); + return NULL; } void vidtv_mux_destroy(struct vidtv_mux *m) @@ -469,6 +540,7 @@ void vidtv_mux_destroy(struct vidtv_mux *m) vidtv_mux_pid_ctx_destroy(m); vidtv_channel_si_destroy(m); vidtv_channels_destroy(m); + kfree(m->network_name); vfree(m->mux_buf); kfree(m); } |