Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Vidtv serves as a reference DVB driver and helps validate the existing APIs
0004  * in the media subsystem. It can also aid developers working on userspace
0005  * applications.
0006  *
0007  * This file contains the code for a 'channel' abstraction.
0008  *
0009  * When vidtv boots, it will create some hardcoded channels.
0010  * Their services will be concatenated to populate the SDT.
0011  * Their programs will be concatenated to populate the PAT
0012  * Their events will be concatenated to populate the EIT
0013  * For each program in the PAT, a PMT section will be created
0014  * The PMT section for a channel will be assigned its streams.
0015  * Every stream will have its corresponding encoder polled to produce TS packets
0016  * These packets may be interleaved by the mux and then delivered to the bridge
0017  *
0018  *
0019  * Copyright (C) 2020 Daniel W. S. Almeida
0020  */
0021 
0022 #include <linux/dev_printk.h>
0023 #include <linux/ratelimit.h>
0024 #include <linux/slab.h>
0025 #include <linux/types.h>
0026 
0027 #include "vidtv_channel.h"
0028 #include "vidtv_common.h"
0029 #include "vidtv_encoder.h"
0030 #include "vidtv_mux.h"
0031 #include "vidtv_psi.h"
0032 #include "vidtv_s302m.h"
0033 
0034 static void vidtv_channel_encoder_destroy(struct vidtv_encoder *e)
0035 {
0036     struct vidtv_encoder *tmp = NULL;
0037     struct vidtv_encoder *curr = e;
0038 
0039     while (curr) {
0040         /* forward the call to the derived type */
0041         tmp = curr;
0042         curr = curr->next;
0043         tmp->destroy(tmp);
0044     }
0045 }
0046 
0047 #define ENCODING_ISO8859_15 "\x0b"
0048 #define TS_NIT_PID  0x10
0049 
0050 /*
0051  * init an audio only channel with a s302m encoder
0052  */
0053 struct vidtv_channel
0054 *vidtv_channel_s302m_init(struct vidtv_channel *head, u16 transport_stream_id)
0055 {
0056     const __be32 s302m_fid              = cpu_to_be32(VIDTV_S302M_FORMAT_IDENTIFIER);
0057     char *event_text = ENCODING_ISO8859_15 "Bagatelle No. 25 in A minor for solo piano, also known as F\xfcr Elise, composed by Ludwig van Beethoven";
0058     char *event_name = ENCODING_ISO8859_15 "Ludwig van Beethoven: F\xfcr Elise";
0059     struct vidtv_s302m_encoder_init_args encoder_args = {};
0060     char *iso_language_code = ENCODING_ISO8859_15 "eng";
0061     char *provider = ENCODING_ISO8859_15 "LinuxTV.org";
0062     char *name = ENCODING_ISO8859_15 "Beethoven";
0063     const u16 s302m_es_pid              = 0x111; /* packet id for the ES */
0064     const u16 s302m_program_pid         = 0x101; /* packet id for PMT*/
0065     const u16 s302m_service_id          = 0x880;
0066     const u16 s302m_program_num         = 0x880;
0067     const u16 s302m_beethoven_event_id  = 1;
0068     struct vidtv_channel *s302m;
0069 
0070     s302m = kzalloc(sizeof(*s302m), GFP_KERNEL);
0071     if (!s302m)
0072         return NULL;
0073 
0074     s302m->name = kstrdup(name, GFP_KERNEL);
0075     if (!s302m->name)
0076         goto free_s302m;
0077 
0078     s302m->service = vidtv_psi_sdt_service_init(NULL, s302m_service_id, false, true);
0079     if (!s302m->service)
0080         goto free_name;
0081 
0082     s302m->service->descriptor = (struct vidtv_psi_desc *)
0083                      vidtv_psi_service_desc_init(NULL,
0084                                  DIGITAL_RADIO_SOUND_SERVICE,
0085                                  name,
0086                                  provider);
0087     if (!s302m->service->descriptor)
0088         goto free_service;
0089 
0090     s302m->transport_stream_id = transport_stream_id;
0091 
0092     s302m->program = vidtv_psi_pat_program_init(NULL,
0093                             s302m_service_id,
0094                             s302m_program_pid);
0095     if (!s302m->program)
0096         goto free_service;
0097 
0098     s302m->program_num = s302m_program_num;
0099 
0100     s302m->streams = vidtv_psi_pmt_stream_init(NULL,
0101                            STREAM_PRIVATE_DATA,
0102                            s302m_es_pid);
0103     if (!s302m->streams)
0104         goto free_program;
0105 
0106     s302m->streams->descriptor = (struct vidtv_psi_desc *)
0107                      vidtv_psi_registration_desc_init(NULL,
0108                                       s302m_fid,
0109                                       NULL,
0110                                       0);
0111     if (!s302m->streams->descriptor)
0112         goto free_streams;
0113 
0114     encoder_args.es_pid = s302m_es_pid;
0115 
0116     s302m->encoders = vidtv_s302m_encoder_init(encoder_args);
0117     if (!s302m->encoders)
0118         goto free_streams;
0119 
0120     s302m->events = vidtv_psi_eit_event_init(NULL, s302m_beethoven_event_id);
0121     if (!s302m->events)
0122         goto free_encoders;
0123     s302m->events->descriptor = (struct vidtv_psi_desc *)
0124                     vidtv_psi_short_event_desc_init(NULL,
0125                                     iso_language_code,
0126                                     event_name,
0127                                     event_text);
0128     if (!s302m->events->descriptor)
0129         goto free_events;
0130 
0131     if (head) {
0132         while (head->next)
0133             head = head->next;
0134 
0135         head->next = s302m;
0136     }
0137 
0138     return s302m;
0139 
0140 free_events:
0141     vidtv_psi_eit_event_destroy(s302m->events);
0142 free_encoders:
0143     vidtv_s302m_encoder_destroy(s302m->encoders);
0144 free_streams:
0145     vidtv_psi_pmt_stream_destroy(s302m->streams);
0146 free_program:
0147     vidtv_psi_pat_program_destroy(s302m->program);
0148 free_service:
0149     vidtv_psi_sdt_service_destroy(s302m->service);
0150 free_name:
0151     kfree(s302m->name);
0152 free_s302m:
0153     kfree(s302m);
0154 
0155     return NULL;
0156 }
0157 
0158 static struct vidtv_psi_table_eit_event
0159 *vidtv_channel_eit_event_cat_into_new(struct vidtv_mux *m)
0160 {
0161     /* Concatenate the events */
0162     const struct vidtv_channel *cur_chnl = m->channels;
0163     struct vidtv_psi_table_eit_event *curr = NULL;
0164     struct vidtv_psi_table_eit_event *head = NULL;
0165     struct vidtv_psi_table_eit_event *tail = NULL;
0166     struct vidtv_psi_desc *desc = NULL;
0167     u16 event_id;
0168 
0169     if (!cur_chnl)
0170         return NULL;
0171 
0172     while (cur_chnl) {
0173         curr = cur_chnl->events;
0174 
0175         if (!curr)
0176             dev_warn_ratelimited(m->dev,
0177                          "No events found for channel %s\n",
0178                          cur_chnl->name);
0179 
0180         while (curr) {
0181             event_id = be16_to_cpu(curr->event_id);
0182             tail = vidtv_psi_eit_event_init(tail, event_id);
0183             if (!tail) {
0184                 vidtv_psi_eit_event_destroy(head);
0185                 return NULL;
0186             }
0187 
0188             desc = vidtv_psi_desc_clone(curr->descriptor);
0189             vidtv_psi_desc_assign(&tail->descriptor, desc);
0190 
0191             if (!head)
0192                 head = tail;
0193 
0194             curr = curr->next;
0195         }
0196 
0197         cur_chnl = cur_chnl->next;
0198     }
0199 
0200     return head;
0201 }
0202 
0203 static struct vidtv_psi_table_sdt_service
0204 *vidtv_channel_sdt_serv_cat_into_new(struct vidtv_mux *m)
0205 {
0206     /* Concatenate the services */
0207     const struct vidtv_channel *cur_chnl = m->channels;
0208 
0209     struct vidtv_psi_table_sdt_service *curr = NULL;
0210     struct vidtv_psi_table_sdt_service *head = NULL;
0211     struct vidtv_psi_table_sdt_service *tail = NULL;
0212 
0213     struct vidtv_psi_desc *desc = NULL;
0214     u16 service_id;
0215 
0216     if (!cur_chnl)
0217         return NULL;
0218 
0219     while (cur_chnl) {
0220         curr = cur_chnl->service;
0221 
0222         if (!curr)
0223             dev_warn_ratelimited(m->dev,
0224                          "No services found for channel %s\n",
0225                          cur_chnl->name);
0226 
0227         while (curr) {
0228             service_id = be16_to_cpu(curr->service_id);
0229             tail = vidtv_psi_sdt_service_init(tail,
0230                               service_id,
0231                               curr->EIT_schedule,
0232                               curr->EIT_present_following);
0233             if (!tail)
0234                 goto free;
0235 
0236             desc = vidtv_psi_desc_clone(curr->descriptor);
0237             if (!desc)
0238                 goto free_tail;
0239             vidtv_psi_desc_assign(&tail->descriptor, desc);
0240 
0241             if (!head)
0242                 head = tail;
0243 
0244             curr = curr->next;
0245         }
0246 
0247         cur_chnl = cur_chnl->next;
0248     }
0249 
0250     return head;
0251 
0252 free_tail:
0253     vidtv_psi_sdt_service_destroy(tail);
0254 free:
0255     vidtv_psi_sdt_service_destroy(head);
0256     return NULL;
0257 }
0258 
0259 static struct vidtv_psi_table_pat_program*
0260 vidtv_channel_pat_prog_cat_into_new(struct vidtv_mux *m)
0261 {
0262     /* Concatenate the programs */
0263     const struct vidtv_channel *cur_chnl = m->channels;
0264     struct vidtv_psi_table_pat_program *curr = NULL;
0265     struct vidtv_psi_table_pat_program *head = NULL;
0266     struct vidtv_psi_table_pat_program *tail = NULL;
0267     u16 serv_id;
0268     u16 pid;
0269 
0270     if (!cur_chnl)
0271         return NULL;
0272 
0273     while (cur_chnl) {
0274         curr = cur_chnl->program;
0275 
0276         if (!curr)
0277             dev_warn_ratelimited(m->dev,
0278                          "No programs found for channel %s\n",
0279                          cur_chnl->name);
0280 
0281         while (curr) {
0282             serv_id = be16_to_cpu(curr->service_id);
0283             pid = vidtv_psi_get_pat_program_pid(curr);
0284             tail = vidtv_psi_pat_program_init(tail,
0285                               serv_id,
0286                               pid);
0287             if (!tail) {
0288                 vidtv_psi_pat_program_destroy(head);
0289                 return NULL;
0290             }
0291 
0292             if (!head)
0293                 head = tail;
0294 
0295             curr = curr->next;
0296         }
0297 
0298         cur_chnl = cur_chnl->next;
0299     }
0300     /* Add the NIT table */
0301     vidtv_psi_pat_program_init(tail, 0, TS_NIT_PID);
0302 
0303     return head;
0304 }
0305 
0306 /*
0307  * Match channels to their respective PMT sections, then assign the
0308  * streams
0309  */
0310 static void
0311 vidtv_channel_pmt_match_sections(struct vidtv_channel *channels,
0312                  struct vidtv_psi_table_pmt **sections,
0313                  u32 nsections)
0314 {
0315     struct vidtv_psi_table_pmt *curr_section = NULL;
0316     struct vidtv_psi_table_pmt_stream *head = NULL;
0317     struct vidtv_psi_table_pmt_stream *tail = NULL;
0318     struct vidtv_psi_table_pmt_stream *s = NULL;
0319     struct vidtv_channel *cur_chnl = channels;
0320     struct vidtv_psi_desc *desc = NULL;
0321     u16 e_pid; /* elementary stream pid */
0322     u16 curr_id;
0323     u32 j;
0324 
0325     while (cur_chnl) {
0326         for (j = 0; j < nsections; ++j) {
0327             curr_section = sections[j];
0328 
0329             if (!curr_section)
0330                 continue;
0331 
0332             curr_id = be16_to_cpu(curr_section->header.id);
0333 
0334             /* we got a match */
0335             if (curr_id == cur_chnl->program_num) {
0336                 s = cur_chnl->streams;
0337 
0338                 /* clone the streams for the PMT */
0339                 while (s) {
0340                     e_pid = vidtv_psi_pmt_stream_get_elem_pid(s);
0341                     tail = vidtv_psi_pmt_stream_init(tail,
0342                                      s->type,
0343                                      e_pid);
0344 
0345                     if (!head)
0346                         head = tail;
0347 
0348                     desc = vidtv_psi_desc_clone(s->descriptor);
0349                     vidtv_psi_desc_assign(&tail->descriptor,
0350                                   desc);
0351 
0352                     s = s->next;
0353                 }
0354 
0355                 vidtv_psi_pmt_stream_assign(curr_section, head);
0356                 break;
0357             }
0358         }
0359 
0360         cur_chnl = cur_chnl->next;
0361     }
0362 }
0363 
0364 static void
0365 vidtv_channel_destroy_service_list(struct vidtv_psi_desc_service_list_entry *e)
0366 {
0367     struct vidtv_psi_desc_service_list_entry *tmp;
0368 
0369     while (e) {
0370         tmp = e;
0371         e = e->next;
0372         kfree(tmp);
0373     }
0374 }
0375 
0376 static struct vidtv_psi_desc_service_list_entry
0377 *vidtv_channel_build_service_list(struct vidtv_psi_table_sdt_service *s)
0378 {
0379     struct vidtv_psi_desc_service_list_entry *curr_e = NULL;
0380     struct vidtv_psi_desc_service_list_entry *head_e = NULL;
0381     struct vidtv_psi_desc_service_list_entry *prev_e = NULL;
0382     struct vidtv_psi_desc *desc = s->descriptor;
0383     struct vidtv_psi_desc_service *s_desc;
0384 
0385     while (s) {
0386         while (desc) {
0387             if (s->descriptor->type != SERVICE_DESCRIPTOR)
0388                 goto next_desc;
0389 
0390             s_desc = (struct vidtv_psi_desc_service *)desc;
0391 
0392             curr_e = kzalloc(sizeof(*curr_e), GFP_KERNEL);
0393             if (!curr_e) {
0394                 vidtv_channel_destroy_service_list(head_e);
0395                 return NULL;
0396             }
0397 
0398             curr_e->service_id = s->service_id;
0399             curr_e->service_type = s_desc->service_type;
0400 
0401             if (!head_e)
0402                 head_e = curr_e;
0403             if (prev_e)
0404                 prev_e->next = curr_e;
0405 
0406             prev_e = curr_e;
0407 
0408 next_desc:
0409             desc = desc->next;
0410         }
0411         s = s->next;
0412     }
0413     return head_e;
0414 }
0415 
0416 int vidtv_channel_si_init(struct vidtv_mux *m)
0417 {
0418     struct vidtv_psi_desc_service_list_entry *service_list = NULL;
0419     struct vidtv_psi_table_pat_program *programs = NULL;
0420     struct vidtv_psi_table_sdt_service *services = NULL;
0421     struct vidtv_psi_table_eit_event *events = NULL;
0422 
0423     m->si.pat = vidtv_psi_pat_table_init(m->transport_stream_id);
0424     if (!m->si.pat)
0425         return -ENOMEM;
0426 
0427     m->si.sdt = vidtv_psi_sdt_table_init(m->network_id,
0428                          m->transport_stream_id);
0429     if (!m->si.sdt)
0430         goto free_pat;
0431 
0432     programs = vidtv_channel_pat_prog_cat_into_new(m);
0433     if (!programs)
0434         goto free_sdt;
0435     services = vidtv_channel_sdt_serv_cat_into_new(m);
0436     if (!services)
0437         goto free_programs;
0438 
0439     events = vidtv_channel_eit_event_cat_into_new(m);
0440     if (!events)
0441         goto free_services;
0442 
0443     /* look for a service descriptor for every service */
0444     service_list = vidtv_channel_build_service_list(services);
0445     if (!service_list)
0446         goto free_events;
0447 
0448     /* use these descriptors to build the NIT */
0449     m->si.nit = vidtv_psi_nit_table_init(m->network_id,
0450                          m->transport_stream_id,
0451                          m->network_name,
0452                          service_list);
0453     if (!m->si.nit)
0454         goto free_service_list;
0455 
0456     m->si.eit = vidtv_psi_eit_table_init(m->network_id,
0457                          m->transport_stream_id,
0458                          programs->service_id);
0459     if (!m->si.eit)
0460         goto free_nit;
0461 
0462     /* assemble all programs and assign to PAT */
0463     vidtv_psi_pat_program_assign(m->si.pat, programs);
0464 
0465     /* assemble all services and assign to SDT */
0466     vidtv_psi_sdt_service_assign(m->si.sdt, services);
0467 
0468     /* assemble all events and assign to EIT */
0469     vidtv_psi_eit_event_assign(m->si.eit, events);
0470 
0471     m->si.pmt_secs = vidtv_psi_pmt_create_sec_for_each_pat_entry(m->si.pat,
0472                                      m->pcr_pid);
0473     if (!m->si.pmt_secs)
0474         goto free_eit;
0475 
0476     vidtv_channel_pmt_match_sections(m->channels,
0477                      m->si.pmt_secs,
0478                      m->si.pat->num_pmt);
0479 
0480     vidtv_channel_destroy_service_list(service_list);
0481 
0482     return 0;
0483 
0484 free_eit:
0485     vidtv_psi_eit_table_destroy(m->si.eit);
0486 free_nit:
0487     vidtv_psi_nit_table_destroy(m->si.nit);
0488 free_service_list:
0489     vidtv_channel_destroy_service_list(service_list);
0490 free_events:
0491     vidtv_psi_eit_event_destroy(events);
0492 free_services:
0493     vidtv_psi_sdt_service_destroy(services);
0494 free_programs:
0495     vidtv_psi_pat_program_destroy(programs);
0496 free_sdt:
0497     vidtv_psi_sdt_table_destroy(m->si.sdt);
0498 free_pat:
0499     vidtv_psi_pat_table_destroy(m->si.pat);
0500     return 0;
0501 }
0502 
0503 void vidtv_channel_si_destroy(struct vidtv_mux *m)
0504 {
0505     u32 i;
0506 
0507     for (i = 0; i < m->si.pat->num_pmt; ++i)
0508         vidtv_psi_pmt_table_destroy(m->si.pmt_secs[i]);
0509 
0510     vidtv_psi_pat_table_destroy(m->si.pat);
0511 
0512     kfree(m->si.pmt_secs);
0513     vidtv_psi_sdt_table_destroy(m->si.sdt);
0514     vidtv_psi_nit_table_destroy(m->si.nit);
0515     vidtv_psi_eit_table_destroy(m->si.eit);
0516 }
0517 
0518 int vidtv_channels_init(struct vidtv_mux *m)
0519 {
0520     /* this is the place to add new 'channels' for vidtv */
0521     m->channels = vidtv_channel_s302m_init(NULL, m->transport_stream_id);
0522 
0523     if (!m->channels)
0524         return -ENOMEM;
0525 
0526     return 0;
0527 }
0528 
0529 void vidtv_channels_destroy(struct vidtv_mux *m)
0530 {
0531     struct vidtv_channel *curr = m->channels;
0532     struct vidtv_channel *tmp = NULL;
0533 
0534     while (curr) {
0535         kfree(curr->name);
0536         vidtv_psi_sdt_service_destroy(curr->service);
0537         vidtv_psi_pat_program_destroy(curr->program);
0538         vidtv_psi_pmt_stream_destroy(curr->streams);
0539         vidtv_channel_encoder_destroy(curr->encoders);
0540         vidtv_psi_eit_event_destroy(curr->events);
0541 
0542         tmp = curr;
0543         curr = curr->next;
0544         kfree(tmp);
0545     }
0546 }