Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * The Virtual DVB test driver serves as a reference DVB driver and helps
0004  * validate the existing APIs in the media subsystem. It can also aid
0005  * developers working on userspace applications.
0006  *
0007  * Copyright (C) 2020 Daniel W. S. Almeida
0008  */
0009 
0010 #define pr_fmt(fmt) KBUILD_MODNAME ":%s, %d: " fmt, __func__, __LINE__
0011 
0012 #include <linux/math64.h>
0013 #include <linux/printk.h>
0014 #include <linux/ratelimit.h>
0015 #include <linux/types.h>
0016 
0017 #include "vidtv_common.h"
0018 #include "vidtv_ts.h"
0019 
0020 static u32 vidtv_ts_write_pcr_bits(u8 *to, u32 to_offset, u64 pcr)
0021 {
0022     /* Exact same from ffmpeg. PCR is a counter driven by a 27Mhz clock */
0023     u64 div;
0024     u64 rem;
0025     u8 *buf = to + to_offset;
0026     u64 pcr_low;
0027     u64 pcr_high;
0028 
0029     div = div64_u64_rem(pcr, 300, &rem);
0030 
0031     pcr_low = rem; /* pcr_low = pcr % 300 */
0032     pcr_high = div; /* pcr_high = pcr / 300 */
0033 
0034     *buf++ = pcr_high >> 25;
0035     *buf++ = pcr_high >> 17;
0036     *buf++ = pcr_high >>  9;
0037     *buf++ = pcr_high >>  1;
0038     *buf++ = pcr_high <<  7 | pcr_low >> 8 | 0x7e;
0039     *buf++ = pcr_low;
0040 
0041     return 6;
0042 }
0043 
0044 void vidtv_ts_inc_cc(u8 *continuity_counter)
0045 {
0046     ++*continuity_counter;
0047     if (*continuity_counter > TS_CC_MAX_VAL)
0048         *continuity_counter = 0;
0049 }
0050 
0051 u32 vidtv_ts_null_write_into(struct null_packet_write_args args)
0052 {
0053     u32 nbytes = 0;
0054     struct vidtv_mpeg_ts ts_header = {};
0055 
0056     ts_header.sync_byte          = TS_SYNC_BYTE;
0057     ts_header.bitfield           = cpu_to_be16(TS_NULL_PACKET_PID);
0058     ts_header.payload            = 1;
0059     ts_header.continuity_counter = *args.continuity_counter;
0060 
0061     /* copy TS header */
0062     nbytes += vidtv_memcpy(args.dest_buf,
0063                    args.dest_offset + nbytes,
0064                    args.buf_sz,
0065                    &ts_header,
0066                    sizeof(ts_header));
0067 
0068     vidtv_ts_inc_cc(args.continuity_counter);
0069 
0070     /* fill the rest with empty data */
0071     nbytes += vidtv_memset(args.dest_buf,
0072                    args.dest_offset + nbytes,
0073                    args.buf_sz,
0074                    TS_FILL_BYTE,
0075                    TS_PACKET_LEN - nbytes);
0076 
0077     /* we should have written exactly _one_ 188byte packet */
0078     if (nbytes != TS_PACKET_LEN)
0079         pr_warn_ratelimited("Expected exactly %d bytes, got %d\n",
0080                     TS_PACKET_LEN,
0081                     nbytes);
0082 
0083     return nbytes;
0084 }
0085 
0086 u32 vidtv_ts_pcr_write_into(struct pcr_write_args args)
0087 {
0088     u32 nbytes = 0;
0089     struct vidtv_mpeg_ts ts_header = {};
0090     struct vidtv_mpeg_ts_adaption ts_adap = {};
0091 
0092     ts_header.sync_byte     = TS_SYNC_BYTE;
0093     ts_header.bitfield      = cpu_to_be16(args.pid);
0094     ts_header.scrambling    = 0;
0095     /* cc is not incremented, but it is needed. see 13818-1 clause 2.4.3.3 */
0096     ts_header.continuity_counter = *args.continuity_counter;
0097     ts_header.payload            = 0;
0098     ts_header.adaptation_field   = 1;
0099 
0100     /* 13818-1 clause 2.4.3.5 */
0101     ts_adap.length = 183;
0102     ts_adap.PCR    = 1;
0103 
0104     /* copy TS header */
0105     nbytes += vidtv_memcpy(args.dest_buf,
0106                    args.dest_offset + nbytes,
0107                    args.buf_sz,
0108                    &ts_header,
0109                    sizeof(ts_header));
0110 
0111     /* write the adap after the TS header */
0112     nbytes += vidtv_memcpy(args.dest_buf,
0113                    args.dest_offset + nbytes,
0114                    args.buf_sz,
0115                    &ts_adap,
0116                    sizeof(ts_adap));
0117 
0118     /* write the PCR optional */
0119     nbytes += vidtv_ts_write_pcr_bits(args.dest_buf,
0120                       args.dest_offset + nbytes,
0121                       args.pcr);
0122 
0123     nbytes += vidtv_memset(args.dest_buf,
0124                    args.dest_offset + nbytes,
0125                    args.buf_sz,
0126                    TS_FILL_BYTE,
0127                    TS_PACKET_LEN - nbytes);
0128 
0129     /* we should have written exactly _one_ 188byte packet */
0130     if (nbytes != TS_PACKET_LEN)
0131         pr_warn_ratelimited("Expected exactly %d bytes, got %d\n",
0132                     TS_PACKET_LEN,
0133                     nbytes);
0134 
0135     return nbytes;
0136 }