1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Vidtv serves as a reference DVB driver and helps validate the existing APIs |
4 | * in the media subsystem. It can also aid developers working on userspace |
5 | * applications. |
6 | * |
7 | * This file contains the code for an AES3 (also known as AES/EBU) encoder. |
8 | * It is based on EBU Tech 3250 and SMPTE 302M technical documents. |
9 | * |
10 | * This encoder currently supports 16bit AES3 subframes using 16bit signed |
11 | * integers. |
12 | * |
13 | * Note: AU stands for Access Unit, and AAU stands for Audio Access Unit |
14 | * |
15 | * Copyright (C) 2020 Daniel W. S. Almeida |
16 | */ |
17 | |
18 | #define pr_fmt(fmt) KBUILD_MODNAME ":%s, %d: " fmt, __func__, __LINE__ |
19 | |
20 | #include <linux/bug.h> |
21 | #include <linux/crc32.h> |
22 | #include <linux/fixp-arith.h> |
23 | #include <linux/jiffies.h> |
24 | #include <linux/kernel.h> |
25 | #include <linux/math64.h> |
26 | #include <linux/printk.h> |
27 | #include <linux/ratelimit.h> |
28 | #include <linux/slab.h> |
29 | #include <linux/string.h> |
30 | #include <linux/types.h> |
31 | #include <linux/vmalloc.h> |
32 | |
33 | #include "vidtv_common.h" |
34 | #include "vidtv_encoder.h" |
35 | #include "vidtv_s302m.h" |
36 | |
37 | #define S302M_SAMPLING_RATE_HZ 48000 |
38 | #define PES_PRIVATE_STREAM_1 0xbd /* PES: private_stream_1 */ |
39 | #define S302M_BLOCK_SZ 192 |
40 | #define S302M_SIN_LUT_NUM_ELEM 1024 |
41 | |
42 | /* these are retrieved empirically from ffmpeg/libavcodec */ |
43 | #define FF_S302M_DEFAULT_NUM_FRAMES 1115 |
44 | #define FF_S302M_DEFAULT_PTS_INCREMENT 2090 |
45 | #define FF_S302M_DEFAULT_PTS_OFFSET 100000 |
46 | |
47 | /* Used by the tone generator: number of samples for PI */ |
48 | #define PI 180 |
49 | |
50 | static const u8 reverse[256] = { |
51 | /* from ffmpeg */ |
52 | 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, |
53 | 0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, |
54 | 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84, 0x44, 0xC4, |
55 | 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, |
56 | 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, |
57 | 0x3C, 0xBC, 0x7C, 0xFC, 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, |
58 | 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA, |
59 | 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, |
60 | 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, |
61 | 0x36, 0xB6, 0x76, 0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, |
62 | 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01, 0x81, 0x41, 0xC1, |
63 | 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1, |
64 | 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, |
65 | 0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, |
66 | 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, 0x0D, 0x8D, 0x4D, 0xCD, |
67 | 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, |
68 | 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, |
69 | 0x33, 0xB3, 0x73, 0xF3, 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, |
70 | 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, 0x07, 0x87, 0x47, 0xC7, |
71 | 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, |
72 | 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, |
73 | 0x3F, 0xBF, 0x7F, 0xFF, |
74 | }; |
75 | |
76 | struct tone_duration { |
77 | enum musical_notes note; |
78 | int duration; |
79 | }; |
80 | |
81 | #define COMPASS 100 /* beats per minute */ |
82 | static const struct tone_duration beethoven_fur_elise[] = { |
83 | { NOTE_SILENT, 512}, |
84 | { NOTE_E_6, 128}, { NOTE_DS_6, 128}, { NOTE_E_6, 128}, |
85 | { NOTE_DS_6, 128}, { NOTE_E_6, 128}, { NOTE_B_5, 128}, |
86 | { NOTE_D_6, 128}, { NOTE_C_6, 128}, { NOTE_A_3, 128}, |
87 | { NOTE_E_4, 128}, { NOTE_A_4, 128}, { NOTE_C_5, 128}, |
88 | { NOTE_E_5, 128}, { NOTE_A_5, 128}, { NOTE_E_3, 128}, |
89 | { NOTE_E_4, 128}, { NOTE_GS_4, 128}, { NOTE_E_5, 128}, |
90 | { NOTE_GS_5, 128}, { NOTE_B_5, 128}, { NOTE_A_3, 128}, |
91 | { NOTE_E_4, 128}, { NOTE_A_4, 128}, { NOTE_E_5, 128}, |
92 | { NOTE_E_6, 128}, { NOTE_DS_6, 128}, { NOTE_E_6, 128}, |
93 | { NOTE_DS_6, 128}, { NOTE_E_6, 128}, { NOTE_B_5, 128}, |
94 | { NOTE_D_6, 128}, { NOTE_C_6, 128}, { NOTE_A_3, 128}, |
95 | { NOTE_E_4, 128}, { NOTE_A_4, 128}, { NOTE_C_5, 128}, |
96 | { NOTE_E_5, 128}, { NOTE_A_5, 128}, { NOTE_E_3, 128}, |
97 | { NOTE_E_4, 128}, { NOTE_GS_4, 128}, { NOTE_E_5, 128}, |
98 | { NOTE_C_6, 128}, { NOTE_B_5, 128}, { NOTE_A_3, 128}, |
99 | { NOTE_E_4, 128}, { NOTE_A_4, 128}, { NOTE_SILENT, 128}, |
100 | |
101 | { NOTE_E_6, 128}, { NOTE_DS_6, 128}, { NOTE_E_6, 128}, |
102 | { NOTE_DS_6, 128}, { NOTE_E_6, 128}, { NOTE_B_5, 128}, |
103 | { NOTE_D_6, 128}, { NOTE_C_6, 128}, { NOTE_A_3, 128}, |
104 | { NOTE_E_4, 128}, { NOTE_A_4, 128}, { NOTE_C_5, 128}, |
105 | { NOTE_E_5, 128}, { NOTE_A_5, 128}, { NOTE_E_3, 128}, |
106 | { NOTE_E_4, 128}, { NOTE_GS_4, 128}, { NOTE_E_5, 128}, |
107 | { NOTE_GS_5, 128}, { NOTE_B_5, 128}, { NOTE_A_3, 128}, |
108 | { NOTE_E_4, 128}, { NOTE_A_4, 128}, { NOTE_E_5, 128}, |
109 | { NOTE_E_6, 128}, { NOTE_DS_6, 128}, { NOTE_E_6, 128}, |
110 | { NOTE_DS_6, 128}, { NOTE_E_6, 128}, { NOTE_B_5, 128}, |
111 | { NOTE_D_6, 128}, { NOTE_C_6, 128}, { NOTE_A_3, 128}, |
112 | { NOTE_E_4, 128}, { NOTE_A_4, 128}, { NOTE_C_5, 128}, |
113 | { NOTE_E_5, 128}, { NOTE_A_5, 128}, { NOTE_E_3, 128}, |
114 | { NOTE_E_4, 128}, { NOTE_GS_4, 128}, { NOTE_E_5, 128}, |
115 | { NOTE_C_6, 128}, { NOTE_B_5, 128}, { NOTE_A_3, 128}, |
116 | { NOTE_E_4, 128}, { NOTE_A_4, 128}, { NOTE_B_4, 128}, |
117 | { NOTE_C_5, 128}, { NOTE_D_5, 128}, { NOTE_C_4, 128}, |
118 | { NOTE_G_4, 128}, { NOTE_C_5, 128}, { NOTE_G_4, 128}, |
119 | { NOTE_F_5, 128}, { NOTE_E_5, 128}, { NOTE_G_3, 128}, |
120 | { NOTE_G_4, 128}, { NOTE_B_3, 128}, { NOTE_F_4, 128}, |
121 | { NOTE_E_5, 128}, { NOTE_D_5, 128}, { NOTE_A_3, 128}, |
122 | { NOTE_E_4, 128}, { NOTE_A_4, 128}, { NOTE_E_4, 128}, |
123 | { NOTE_D_5, 128}, { NOTE_C_5, 128}, { NOTE_E_3, 128}, |
124 | { NOTE_E_4, 128}, { NOTE_E_5, 128}, { NOTE_E_5, 128}, |
125 | { NOTE_E_6, 128}, { NOTE_E_5, 128}, { NOTE_E_6, 128}, |
126 | { NOTE_E_5, 128}, { NOTE_E_5, 128}, { NOTE_DS_5, 128}, |
127 | { NOTE_E_5, 128}, { NOTE_DS_6, 128}, { NOTE_E_6, 128}, |
128 | { NOTE_DS_5, 128}, { NOTE_E_5, 128}, { NOTE_DS_6, 128}, |
129 | { NOTE_E_6, 128}, { NOTE_DS_6, 128}, { NOTE_E_6, 128}, |
130 | { NOTE_DS_6, 128}, { NOTE_E_6, 128}, { NOTE_B_5, 128}, |
131 | { NOTE_D_6, 128}, { NOTE_C_6, 128}, { NOTE_A_3, 128}, |
132 | { NOTE_E_4, 128}, { NOTE_A_4, 128}, { NOTE_C_5, 128}, |
133 | { NOTE_E_5, 128}, { NOTE_A_5, 128}, { NOTE_E_3, 128}, |
134 | { NOTE_E_4, 128}, { NOTE_GS_4, 128}, { NOTE_E_5, 128}, |
135 | { NOTE_GS_5, 128}, { NOTE_B_5, 128}, { NOTE_A_3, 128}, |
136 | { NOTE_E_4, 128}, { NOTE_A_4, 128}, { NOTE_E_5, 128}, |
137 | { NOTE_E_6, 128}, { NOTE_DS_6, 128}, { NOTE_E_6, 128}, |
138 | { NOTE_DS_6, 128}, { NOTE_E_6, 128}, { NOTE_B_5, 128}, |
139 | { NOTE_D_6, 128}, { NOTE_C_6, 128}, { NOTE_A_3, 128}, |
140 | { NOTE_E_4, 128}, { NOTE_A_4, 128}, { NOTE_C_5, 128}, |
141 | { NOTE_E_5, 128}, { NOTE_A_5, 128}, { NOTE_E_3, 128}, |
142 | { NOTE_E_4, 128}, { NOTE_GS_4, 128}, { NOTE_E_5, 128}, |
143 | { NOTE_C_6, 128}, { NOTE_B_5, 128}, { NOTE_A_5, 512}, |
144 | { NOTE_SILENT, 256}, |
145 | }; |
146 | |
147 | static struct vidtv_access_unit *vidtv_s302m_access_unit_init(struct vidtv_access_unit *head) |
148 | { |
149 | struct vidtv_access_unit *au; |
150 | |
151 | au = kzalloc(size: sizeof(*au), GFP_KERNEL); |
152 | if (!au) |
153 | return NULL; |
154 | |
155 | if (head) { |
156 | while (head->next) |
157 | head = head->next; |
158 | |
159 | head->next = au; |
160 | } |
161 | |
162 | return au; |
163 | } |
164 | |
165 | static void vidtv_s302m_access_unit_destroy(struct vidtv_encoder *e) |
166 | { |
167 | struct vidtv_access_unit *head = e->access_units; |
168 | struct vidtv_access_unit *tmp = NULL; |
169 | |
170 | while (head) { |
171 | tmp = head; |
172 | head = head->next; |
173 | kfree(objp: tmp); |
174 | } |
175 | |
176 | e->access_units = NULL; |
177 | } |
178 | |
179 | static void vidtv_s302m_alloc_au(struct vidtv_encoder *e) |
180 | { |
181 | struct vidtv_access_unit *sync_au = NULL; |
182 | struct vidtv_access_unit *temp = NULL; |
183 | |
184 | if (e->sync && e->sync->is_video_encoder) { |
185 | sync_au = e->sync->access_units; |
186 | |
187 | while (sync_au) { |
188 | temp = vidtv_s302m_access_unit_init(head: e->access_units); |
189 | if (!e->access_units) |
190 | e->access_units = temp; |
191 | |
192 | sync_au = sync_au->next; |
193 | } |
194 | |
195 | return; |
196 | } |
197 | |
198 | e->access_units = vidtv_s302m_access_unit_init(NULL); |
199 | } |
200 | |
201 | static void |
202 | vidtv_s302m_compute_sample_count_from_video(struct vidtv_encoder *e) |
203 | { |
204 | struct vidtv_access_unit *sync_au = e->sync->access_units; |
205 | struct vidtv_access_unit *au = e->access_units; |
206 | u32 sample_duration_usecs; |
207 | u32 vau_duration_usecs; |
208 | u32 s; |
209 | |
210 | vau_duration_usecs = USEC_PER_SEC / e->sync->sampling_rate_hz; |
211 | sample_duration_usecs = USEC_PER_SEC / e->sampling_rate_hz; |
212 | |
213 | while (au && sync_au) { |
214 | s = DIV_ROUND_UP(vau_duration_usecs, sample_duration_usecs); |
215 | au->num_samples = s; |
216 | au = au->next; |
217 | sync_au = sync_au->next; |
218 | } |
219 | } |
220 | |
221 | static void vidtv_s302m_compute_pts_from_video(struct vidtv_encoder *e) |
222 | { |
223 | struct vidtv_access_unit *au = e->access_units; |
224 | struct vidtv_access_unit *sync_au = e->sync->access_units; |
225 | |
226 | /* use the same pts from the video access unit*/ |
227 | while (au && sync_au) { |
228 | au->pts = sync_au->pts; |
229 | au = au->next; |
230 | sync_au = sync_au->next; |
231 | } |
232 | } |
233 | |
234 | static u16 vidtv_s302m_get_sample(struct vidtv_encoder *e) |
235 | { |
236 | u16 sample; |
237 | int pos; |
238 | struct vidtv_s302m_ctx *ctx = e->ctx; |
239 | |
240 | if (!e->src_buf) { |
241 | /* |
242 | * Simple tone generator: play the tones at the |
243 | * beethoven_fur_elise array. |
244 | */ |
245 | if (ctx->last_duration <= 0) { |
246 | if (e->src_buf_offset >= ARRAY_SIZE(beethoven_fur_elise)) |
247 | e->src_buf_offset = 0; |
248 | |
249 | ctx->last_tone = beethoven_fur_elise[e->src_buf_offset].note; |
250 | ctx->last_duration = beethoven_fur_elise[e->src_buf_offset].duration * |
251 | S302M_SAMPLING_RATE_HZ / COMPASS / 5; |
252 | e->src_buf_offset++; |
253 | ctx->note_offset = 0; |
254 | } else { |
255 | ctx->last_duration--; |
256 | } |
257 | |
258 | /* Handle pause notes */ |
259 | if (!ctx->last_tone) |
260 | return 0x8000; |
261 | |
262 | pos = (2 * PI * ctx->note_offset * ctx->last_tone) / S302M_SAMPLING_RATE_HZ; |
263 | ctx->note_offset++; |
264 | |
265 | return (fixp_sin32(degrees: pos % (2 * PI)) >> 16) + 0x8000; |
266 | } |
267 | |
268 | /* bug somewhere */ |
269 | if (e->src_buf_offset > e->src_buf_sz) { |
270 | pr_err_ratelimited("overflow detected: %d > %d, wrapping.\n" , |
271 | e->src_buf_offset, |
272 | e->src_buf_sz); |
273 | |
274 | e->src_buf_offset = 0; |
275 | } |
276 | |
277 | if (e->src_buf_offset >= e->src_buf_sz) { |
278 | /* let the source know we are out of data */ |
279 | if (e->last_sample_cb) |
280 | e->last_sample_cb(e->sample_count); |
281 | |
282 | e->src_buf_offset = 0; |
283 | } |
284 | |
285 | sample = *(u16 *)(e->src_buf + e->src_buf_offset); |
286 | |
287 | return sample; |
288 | } |
289 | |
290 | static u32 vidtv_s302m_write_frame(struct vidtv_encoder *e, |
291 | u16 sample) |
292 | { |
293 | struct vidtv_s302m_ctx *ctx = e->ctx; |
294 | struct vidtv_s302m_frame_16 f = {}; |
295 | u32 nbytes = 0; |
296 | |
297 | /* from ffmpeg: see s302enc.c */ |
298 | |
299 | u8 vucf = ctx->frame_index == 0 ? 0x10 : 0; |
300 | |
301 | f.data[0] = sample & 0xFF; |
302 | f.data[1] = (sample & 0xFF00) >> 8; |
303 | f.data[2] = ((sample & 0x0F) << 4) | vucf; |
304 | f.data[3] = (sample & 0x0FF0) >> 4; |
305 | f.data[4] = (sample & 0xF000) >> 12; |
306 | |
307 | f.data[0] = reverse[f.data[0]]; |
308 | f.data[1] = reverse[f.data[1]]; |
309 | f.data[2] = reverse[f.data[2]]; |
310 | f.data[3] = reverse[f.data[3]]; |
311 | f.data[4] = reverse[f.data[4]]; |
312 | |
313 | nbytes += vidtv_memcpy(to: e->encoder_buf, |
314 | to_offset: e->encoder_buf_offset, |
315 | VIDTV_S302M_BUF_SZ, |
316 | from: &f, |
317 | len: sizeof(f)); |
318 | |
319 | e->encoder_buf_offset += nbytes; |
320 | |
321 | ctx->frame_index++; |
322 | if (ctx->frame_index >= S302M_BLOCK_SZ) |
323 | ctx->frame_index = 0; |
324 | |
325 | return nbytes; |
326 | } |
327 | |
328 | static u32 vidtv_s302m_write_h(struct vidtv_encoder *e, u32 p_sz) |
329 | { |
330 | struct vidtv_smpte_s302m_es h = {}; |
331 | u32 nbytes = 0; |
332 | |
333 | /* 2 channels, ident: 0, 16 bits per sample */ |
334 | h.bitfield = cpu_to_be32((p_sz << 16)); |
335 | |
336 | nbytes += vidtv_memcpy(to: e->encoder_buf, |
337 | to_offset: e->encoder_buf_offset, |
338 | to_size: e->encoder_buf_sz, |
339 | from: &h, |
340 | len: sizeof(h)); |
341 | |
342 | e->encoder_buf_offset += nbytes; |
343 | return nbytes; |
344 | } |
345 | |
346 | static void vidtv_s302m_write_frames(struct vidtv_encoder *e) |
347 | { |
348 | struct vidtv_access_unit *au = e->access_units; |
349 | struct vidtv_s302m_ctx *ctx = e->ctx; |
350 | u32 nbytes_per_unit = 0; |
351 | u32 nbytes = 0; |
352 | u32 au_sz = 0; |
353 | u16 sample; |
354 | u32 j; |
355 | |
356 | while (au) { |
357 | au_sz = au->num_samples * |
358 | sizeof(struct vidtv_s302m_frame_16); |
359 | |
360 | nbytes_per_unit = vidtv_s302m_write_h(e, p_sz: au_sz); |
361 | |
362 | for (j = 0; j < au->num_samples; ++j) { |
363 | sample = vidtv_s302m_get_sample(e); |
364 | nbytes_per_unit += vidtv_s302m_write_frame(e, sample); |
365 | |
366 | if (e->src_buf) |
367 | e->src_buf_offset += sizeof(u16); |
368 | |
369 | e->sample_count++; |
370 | } |
371 | |
372 | au->nbytes = nbytes_per_unit; |
373 | |
374 | if (au_sz + sizeof(struct vidtv_smpte_s302m_es) != nbytes_per_unit) { |
375 | pr_warn_ratelimited("write size was %u, expected %zu\n" , |
376 | nbytes_per_unit, |
377 | au_sz + sizeof(struct vidtv_smpte_s302m_es)); |
378 | } |
379 | |
380 | nbytes += nbytes_per_unit; |
381 | au->offset = nbytes - nbytes_per_unit; |
382 | |
383 | nbytes_per_unit = 0; |
384 | ctx->au_count++; |
385 | |
386 | au = au->next; |
387 | } |
388 | } |
389 | |
390 | static void *vidtv_s302m_encode(struct vidtv_encoder *e) |
391 | { |
392 | struct vidtv_s302m_ctx *ctx = e->ctx; |
393 | |
394 | /* |
395 | * According to SMPTE 302M, an audio access unit is specified as those |
396 | * AES3 words that are associated with a corresponding video frame. |
397 | * Therefore, there is one audio access unit for every video access unit |
398 | * in the corresponding video encoder ('sync'), using the same values |
399 | * for PTS as used by the video encoder. |
400 | * |
401 | * Assuming that it is also possible to send audio without any |
402 | * associated video, as in a radio-like service, a single audio access unit |
403 | * is created with values for 'num_samples' and 'pts' taken empirically from |
404 | * ffmpeg |
405 | */ |
406 | |
407 | vidtv_s302m_access_unit_destroy(e); |
408 | vidtv_s302m_alloc_au(e); |
409 | |
410 | if (e->sync && e->sync->is_video_encoder) { |
411 | vidtv_s302m_compute_sample_count_from_video(e); |
412 | vidtv_s302m_compute_pts_from_video(e); |
413 | } else { |
414 | e->access_units->num_samples = FF_S302M_DEFAULT_NUM_FRAMES; |
415 | e->access_units->pts = (ctx->au_count * FF_S302M_DEFAULT_PTS_INCREMENT) + |
416 | FF_S302M_DEFAULT_PTS_OFFSET; |
417 | } |
418 | |
419 | vidtv_s302m_write_frames(e); |
420 | |
421 | return e->encoder_buf; |
422 | } |
423 | |
424 | static u32 vidtv_s302m_clear(struct vidtv_encoder *e) |
425 | { |
426 | struct vidtv_access_unit *au = e->access_units; |
427 | u32 count = 0; |
428 | |
429 | while (au) { |
430 | count++; |
431 | au = au->next; |
432 | } |
433 | |
434 | vidtv_s302m_access_unit_destroy(e); |
435 | memset(e->encoder_buf, 0, VIDTV_S302M_BUF_SZ); |
436 | e->encoder_buf_offset = 0; |
437 | |
438 | return count; |
439 | } |
440 | |
441 | struct vidtv_encoder |
442 | *vidtv_s302m_encoder_init(struct vidtv_s302m_encoder_init_args args) |
443 | { |
444 | u32 priv_sz = sizeof(struct vidtv_s302m_ctx); |
445 | struct vidtv_s302m_ctx *ctx; |
446 | struct vidtv_encoder *e; |
447 | |
448 | e = kzalloc(size: sizeof(*e), GFP_KERNEL); |
449 | if (!e) |
450 | return NULL; |
451 | |
452 | e->id = S302M; |
453 | |
454 | if (args.name) |
455 | e->name = kstrdup(s: args.name, GFP_KERNEL); |
456 | |
457 | e->encoder_buf = vzalloc(VIDTV_S302M_BUF_SZ); |
458 | if (!e->encoder_buf) |
459 | goto out_kfree_e; |
460 | |
461 | e->encoder_buf_sz = VIDTV_S302M_BUF_SZ; |
462 | e->encoder_buf_offset = 0; |
463 | |
464 | e->sample_count = 0; |
465 | |
466 | e->src_buf = (args.src_buf) ? args.src_buf : NULL; |
467 | e->src_buf_sz = (args.src_buf) ? args.src_buf_sz : 0; |
468 | e->src_buf_offset = 0; |
469 | |
470 | e->is_video_encoder = false; |
471 | |
472 | ctx = kzalloc(size: priv_sz, GFP_KERNEL); |
473 | if (!ctx) |
474 | goto out_kfree_buf; |
475 | |
476 | e->ctx = ctx; |
477 | ctx->last_duration = 0; |
478 | |
479 | e->encode = vidtv_s302m_encode; |
480 | e->clear = vidtv_s302m_clear; |
481 | |
482 | e->es_pid = cpu_to_be16(args.es_pid); |
483 | e->stream_id = cpu_to_be16(PES_PRIVATE_STREAM_1); |
484 | |
485 | e->sync = args.sync; |
486 | e->sampling_rate_hz = S302M_SAMPLING_RATE_HZ; |
487 | |
488 | e->last_sample_cb = args.last_sample_cb; |
489 | |
490 | e->destroy = vidtv_s302m_encoder_destroy; |
491 | |
492 | if (args.head) { |
493 | while (args.head->next) |
494 | args.head = args.head->next; |
495 | |
496 | args.head->next = e; |
497 | } |
498 | |
499 | e->next = NULL; |
500 | |
501 | return e; |
502 | |
503 | out_kfree_buf: |
504 | vfree(addr: e->encoder_buf); |
505 | |
506 | out_kfree_e: |
507 | kfree(objp: e->name); |
508 | kfree(objp: e); |
509 | return NULL; |
510 | } |
511 | |
512 | void vidtv_s302m_encoder_destroy(struct vidtv_encoder *e) |
513 | { |
514 | if (e->id != S302M) { |
515 | pr_err_ratelimited("Encoder type mismatch, skipping.\n" ); |
516 | return; |
517 | } |
518 | |
519 | vidtv_s302m_access_unit_destroy(e); |
520 | kfree(objp: e->name); |
521 | vfree(addr: e->encoder_buf); |
522 | kfree(objp: e->ctx); |
523 | kfree(objp: e); |
524 | } |
525 | |