File Index
Files and directories
Sign in
FILE

av7110_ipack.c

File preview with syntax highlighting.

linux-6.19.14/drivers/staging/media/av7110/av7110_ipack.c C
  1// SPDX-License-Identifier: GPL-2.0
  2#include "dvb_filter.h"
  3#include "av7110_ipack.h"
  4#include <linux/string.h>	/* for memcpy() */
  5#include <linux/vmalloc.h>
  6
  7void av7110_ipack_reset(struct ipack *p)
  8{
  9	p->found = 0;
 10	p->cid = 0;
 11	p->plength = 0;
 12	p->flag1 = 0;
 13	p->flag2 = 0;
 14	p->hlength = 0;
 15	p->mpeg = 0;
 16	p->check = 0;
 17	p->which = 0;
 18	p->done = 0;
 19	p->count = 0;
 20}
 21
 22int av7110_ipack_init(struct ipack *p, int size,
 23		      void (*func)(u8 *buf, int size, void *priv))
 24{
 25	p->buf = vmalloc(size);
 26	if (!p->buf)
 27		return -ENOMEM;
 28	p->size = size;
 29	p->func = func;
 30	p->repack_subids = 0;
 31	av7110_ipack_reset(p);
 32	return 0;
 33}
 34
 35void av7110_ipack_free(struct ipack *p)
 36{
 37	vfree(p->buf);
 38}
 39
 40static void send_ipack(struct ipack *p)
 41{
 42	int off;
 43	struct dvb_audio_info ai;
 44	int ac3_off = 0;
 45	int streamid = 0;
 46	int nframes = 0;
 47	int f = 0;
 48
 49	switch (p->mpeg) {
 50	case 2:
 51		if (p->count < 10)
 52			return;
 53		p->buf[3] = p->cid;
 54		p->buf[4] = (u8)(((p->count - 6) & 0xff00) >> 8);
 55		p->buf[5] = (u8)((p->count - 6) & 0x00ff);
 56		if (p->repack_subids && p->cid == PRIVATE_STREAM1) {
 57			off = 9 + p->buf[8];
 58			streamid = p->buf[off];
 59			if ((streamid & 0xf8) == 0x80) {
 60				ai.off = 0;
 61				ac3_off = ((p->buf[off + 2] << 8) |
 62					   p->buf[off + 3]);
 63				if (ac3_off < p->count)
 64					f = dvb_filter_get_ac3info(p->buf + off + 3 + ac3_off,
 65								   p->count - ac3_off, &ai, 0);
 66				if (!f) {
 67					nframes = (p->count - off - 3 - ac3_off) /
 68						ai.framesize + 1;
 69					p->buf[off + 2] = (ac3_off >> 8) & 0xff;
 70					p->buf[off + 3] = (ac3_off) & 0xff;
 71					p->buf[off + 1] = nframes;
 72					ac3_off +=  nframes * ai.framesize - p->count;
 73				}
 74			}
 75		}
 76		p->func(p->buf, p->count, p->data);
 77
 78		p->buf[6] = 0x80;
 79		p->buf[7] = 0x00;
 80		p->buf[8] = 0x00;
 81		p->count = 9;
 82		if (p->repack_subids && p->cid == PRIVATE_STREAM1 &&
 83		    (streamid & 0xf8) == 0x80) {
 84			p->count += 4;
 85			p->buf[9] = streamid;
 86			p->buf[10] = (ac3_off >> 8) & 0xff;
 87			p->buf[11] = (ac3_off) & 0xff;
 88			p->buf[12] = 0;
 89		}
 90		break;
 91
 92	case 1:
 93		if (p->count < 8)
 94			return;
 95		p->buf[3] = p->cid;
 96		p->buf[4] = (u8)(((p->count - 6) & 0xff00) >> 8);
 97		p->buf[5] = (u8)((p->count - 6) & 0x00ff);
 98		p->func(p->buf, p->count, p->data);
 99
100		p->buf[6] = 0x0f;
101		p->count = 7;
102		break;
103	}
104}
105
106void av7110_ipack_flush(struct ipack *p)
107{
108	if (p->plength != MMAX_PLENGTH - 6 || p->found <= 6)
109		return;
110	p->plength = p->found - 6;
111	p->found = 0;
112	send_ipack(p);
113	av7110_ipack_reset(p);
114}
115
116static void write_ipack(struct ipack *p, const u8 *data, int count)
117{
118	u8 headr[3] = { 0x00, 0x00, 0x01 };
119
120	if (p->count < 6) {
121		memcpy(p->buf, headr, 3);
122		p->count = 6;
123	}
124
125	if (p->count + count < p->size) {
126		memcpy(p->buf + p->count, data, count);
127		p->count += count;
128	} else {
129		int rest = p->size - p->count;
130
131		memcpy(p->buf + p->count, data, rest);
132		p->count += rest;
133		send_ipack(p);
134		if (count - rest > 0)
135			write_ipack(p, data + rest, count - rest);
136	}
137}
138
139int av7110_ipack_instant_repack(const u8 *buf, int count, struct ipack *p)
140{
141	int l;
142	int c = 0;
143
144	while (c < count && (p->mpeg == 0 ||
145			     (p->mpeg == 1 && p->found < 7) ||
146			     (p->mpeg == 2 && p->found < 9)) &&
147			     (p->found < 5 || !p->done)) {
148		switch (p->found) {
149		case 0:
150		case 1:
151			if (buf[c] == 0x00)
152				p->found++;
153			else
154				p->found = 0;
155			c++;
156			break;
157		case 2:
158			if (buf[c] == 0x01)
159				p->found++;
160			else if (buf[c] == 0)
161				p->found = 2;
162			else
163				p->found = 0;
164			c++;
165			break;
166		case 3:
167			p->cid = 0;
168			switch (buf[c]) {
169			case PROG_STREAM_MAP:
170			case PRIVATE_STREAM2:
171			case PROG_STREAM_DIR:
172			case ECM_STREAM:
173			case EMM_STREAM:
174			case PADDING_STREAM:
175			case DSM_CC_STREAM:
176			case ISO13522_STREAM:
177				p->done = 1;
178				fallthrough;
179			case PRIVATE_STREAM1:
180			case VIDEO_STREAM_S ... VIDEO_STREAM_E:
181			case AUDIO_STREAM_S ... AUDIO_STREAM_E:
182				p->found++;
183				p->cid = buf[c];
184				c++;
185				break;
186			default:
187				p->found = 0;
188				break;
189			}
190			break;
191
192		case 4:
193			if (count - c > 1) {
194				p->plen[0] = buf[c];
195				c++;
196				p->plen[1] = buf[c];
197				c++;
198				p->found += 2;
199				p->plength = (p->plen[0] << 8) | p->plen[1];
200			} else {
201				p->plen[0] = buf[c];
202				p->found++;
203				return count;
204			}
205			break;
206		case 5:
207			p->plen[1] = buf[c];
208			c++;
209			p->found++;
210			p->plength = (p->plen[0] << 8) | p->plen[1];
211			break;
212		case 6:
213			if (!p->done) {
214				p->flag1 = buf[c];
215				c++;
216				p->found++;
217				if ((p->flag1 & 0xc0) == 0x80) {
218					p->mpeg = 2;
219				} else {
220					p->hlength = 0;
221					p->which = 0;
222					p->mpeg = 1;
223					p->flag2 = 0;
224				}
225			}
226			break;
227
228		case 7:
229			if (!p->done && p->mpeg == 2) {
230				p->flag2 = buf[c];
231				c++;
232				p->found++;
233			}
234			break;
235
236		case 8:
237			if (!p->done && p->mpeg == 2) {
238				p->hlength = buf[c];
239				c++;
240				p->found++;
241			}
242			break;
243		}
244	}
245
246	if (c == count)
247		return count;
248
249	if (!p->plength)
250		p->plength = MMAX_PLENGTH - 6;
251
252	if (!(p->done || ((p->mpeg == 2 && p->found >= 9) ||
253			  (p->mpeg == 1 && p->found >= 7))))
254		return count;
255
256	switch (p->cid) {
257	case AUDIO_STREAM_S ... AUDIO_STREAM_E:
258	case VIDEO_STREAM_S ... VIDEO_STREAM_E:
259	case PRIVATE_STREAM1:
260		if (p->mpeg == 2 && p->found == 9) {
261			write_ipack(p, &p->flag1, 1);
262			write_ipack(p, &p->flag2, 1);
263			write_ipack(p, &p->hlength, 1);
264		}
265
266		if (p->mpeg == 1 && p->found == 7)
267			write_ipack(p, &p->flag1, 1);
268
269		if (p->mpeg == 2 && (p->flag2 & PTS_ONLY) && p->found < 14) {
270			while (c < count && p->found < 14) {
271				p->pts[p->found - 9] = buf[c];
272				write_ipack(p, buf + c, 1);
273				c++;
274				p->found++;
275			}
276			if (c == count)
277				return count;
278		}
279
280		if (p->mpeg == 1 && p->which < 2000) {
281			if (p->found == 7) {
282				p->check = p->flag1;
283				p->hlength = 1;
284			}
285
286			while (!p->which && c < count && p->check == 0xff) {
287				p->check = buf[c];
288				write_ipack(p, buf + c, 1);
289				c++;
290				p->found++;
291				p->hlength++;
292			}
293
294			if (c == count)
295				return count;
296
297			if ((p->check & 0xc0) == 0x40 && !p->which) {
298				p->check = buf[c];
299				write_ipack(p, buf + c, 1);
300				c++;
301				p->found++;
302				p->hlength++;
303
304				p->which = 1;
305				if (c == count)
306					return count;
307				p->check = buf[c];
308				write_ipack(p, buf + c, 1);
309				c++;
310				p->found++;
311				p->hlength++;
312				p->which = 2;
313				if (c == count)
314					return count;
315			}
316
317			if (p->which == 1) {
318				p->check = buf[c];
319				write_ipack(p, buf + c, 1);
320				c++;
321				p->found++;
322				p->hlength++;
323				p->which = 2;
324				if (c == count)
325					return count;
326			}
327
328			if ((p->check & 0x30) && p->check != 0xff) {
329				p->flag2 = (p->check & 0xf0) << 2;
330				p->pts[0] = p->check;
331				p->which = 3;
332			}
333
334			if (c == count)
335				return count;
336			if (p->which > 2) {
337				if ((p->flag2 & PTS_DTS_FLAGS) == PTS_ONLY) {
338					while (c < count && p->which < 7) {
339						p->pts[p->which - 2] = buf[c];
340						write_ipack(p, buf + c, 1);
341						c++;
342						p->found++;
343						p->which++;
344						p->hlength++;
345					}
346					if (c == count)
347						return count;
348				} else if ((p->flag2 & PTS_DTS_FLAGS) == PTS_DTS) {
349					while (c < count && p->which < 12) {
350						if (p->which < 7)
351							p->pts[p->which - 2] = buf[c];
352						write_ipack(p, buf + c, 1);
353						c++;
354						p->found++;
355						p->which++;
356						p->hlength++;
357					}
358					if (c == count)
359						return count;
360				}
361				p->which = 2000;
362			}
363		}
364
365		while (c < count && p->found < p->plength + 6) {
366			l = count - c;
367			if (l + p->found > p->plength + 6)
368				l = p->plength + 6 - p->found;
369			write_ipack(p, buf + c, l);
370			p->found += l;
371			c += l;
372		}
373		break;
374	}
375
376	if (p->done) {
377		if (p->found + count - c < p->plength + 6) {
378			p->found += count - c;
379			c = count;
380		} else {
381			c += p->plength + 6 - p->found;
382			p->found = p->plength + 6;
383		}
384	}
385
386	if (p->plength && p->found == p->plength + 6) {
387		send_ipack(p);
388		av7110_ipack_reset(p);
389		if (c < count)
390			av7110_ipack_instant_repack(buf + c, count - c, p);
391	}
392
393	return count;
394}
~/ Read-only file preview.