static size_t cx18_copy_buf_to_user(struct cx18_stream *s, struct cx18_buffer *buf, char __user *ubuf, size_t ucount) { struct cx18 *cx = s->cx; size_t len = buf->bytesused - buf->readpos; if (len > ucount) len = ucount; if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG && cx->vbi.sliced_in->service_set && buf != &cx->vbi.sliced_mpeg_buf) { const char *start = buf->buf + buf->readpos; const char *p = start + 1; const u8 *q; u8 ch = cx->search_pack_header ? 0xba : 0xe0; int stuffing, i; while (start + len > p) { q = memchr(p, 0, start + len - p); if (q == NULL) break; p = q + 1; if ((char *)q + 15 >= buf->buf + buf->bytesused || q[1] != 0 || q[2] != 1 || q[3] != ch) continue; if (!cx->search_pack_header) { if ((q[6] & 0xc0) != 0x80) continue; if (((q[7] & 0xc0) == 0x80 && (q[9] & 0xf0) == 0x20) || ((q[7] & 0xc0) == 0xc0 && (q[9] & 0xf0) == 0x30)) { ch = 0xba; cx->search_pack_header = 1; p = q + 9; } continue; } stuffing = q[13] & 7; /* all stuffing bytes must be 0xff */ for (i = 0; i < stuffing; i++) if (q[14 + i] != 0xff) break; if (i == stuffing && (q[4] & 0xc4) == 0x44 && (q[12] & 3) == 3 && q[14 + stuffing] == 0 && q[15 + stuffing] == 0 && q[16 + stuffing] == 1) { cx->search_pack_header = 0; len = (char *)q - start; cx18_setup_sliced_vbi_buf(cx); break; } } } if (copy_to_user(ubuf, (u8 *)buf->buf + buf->readpos, len)) { CX18_DEBUG_WARN("copy %zd bytes to user failed for %s\n", len, s->name); return -EFAULT; } buf->readpos += len; if (s->type == CX18_ENC_STREAM_TYPE_MPG && buf != &cx->vbi.sliced_mpeg_buf) cx->mpg_data_received += len; return len; }
static size_t cx18_copy_buf_to_user(struct cx18_stream *s, struct cx18_buffer *buf, char __user *ubuf, size_t ucount) { struct cx18 *cx = s->cx; size_t len = buf->bytesused - buf->readpos; if (len > ucount) len = ucount; if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG && !cx18_raw_vbi(cx) && buf != &cx->vbi.sliced_mpeg_buf) { /* * Try to find a good splice point in the PS, just before * an MPEG-2 Program Pack start code, and provide only * up to that point to the user, so it's easy to insert VBI data * the next time around. * * This will not work for an MPEG-2 TS and has only been * verified by analysis to work for an MPEG-2 PS. Helen Buus * pointed out this works for the CX23416 MPEG-2 DVD compatible * stream, and research indicates both the MPEG 2 SVCD and DVD * stream types use an MPEG-2 PS container. */ /* * An MPEG-2 Program Stream (PS) is a series of * MPEG-2 Program Packs terminated by an * MPEG Program End Code after the last Program Pack. * A Program Pack may hold a PS System Header packet and any * number of Program Elementary Stream (PES) Packets */ const char *start = buf->buf + buf->readpos; const char *p = start + 1; const u8 *q; u8 ch = cx->search_pack_header ? 0xba : 0xe0; int stuffing, i; while (start + len > p) { /* Scan for a 0 to find a potential MPEG-2 start code */ q = memchr(p, 0, start + len - p); if (q == NULL) break; p = q + 1; /* * Keep looking if not a * MPEG-2 Pack header start code: 0x00 0x00 0x01 0xba * or MPEG-2 video PES start code: 0x00 0x00 0x01 0xe0 */ if ((char *)q + 15 >= buf->buf + buf->bytesused || q[1] != 0 || q[2] != 1 || q[3] != ch) continue; /* If expecting the primary video PES */ if (!cx->search_pack_header) { /* Continue if it couldn't be a PES packet */ if ((q[6] & 0xc0) != 0x80) continue; /* Check if a PTS or PTS & DTS follow */ if (((q[7] & 0xc0) == 0x80 && /* PTS only */ (q[9] & 0xf0) == 0x20) || /* PTS only */ ((q[7] & 0xc0) == 0xc0 && /* PTS & DTS */ (q[9] & 0xf0) == 0x30)) { /* DTS follows */ /* Assume we found the video PES hdr */ ch = 0xba; /* next want a Program Pack*/ cx->search_pack_header = 1; p = q + 9; /* Skip this video PES hdr */ } continue; } /* We may have found a Program Pack start code */ /* Get the count of stuffing bytes & verify them */ stuffing = q[13] & 7; /* all stuffing bytes must be 0xff */ for (i = 0; i < stuffing; i++) if (q[14 + i] != 0xff) break; if (i == stuffing && /* right number of stuffing bytes*/ (q[4] & 0xc4) == 0x44 && /* marker check */ (q[12] & 3) == 3 && /* marker check */ q[14 + stuffing] == 0 && /* PES Pack or Sys Hdr */ q[15 + stuffing] == 0 && q[16 + stuffing] == 1) { /* We declare we actually found a Program Pack*/ cx->search_pack_header = 0; /* expect vid PES */ len = (char *)q - start; cx18_setup_sliced_vbi_buf(cx); break; } } } if (copy_to_user(ubuf, (u8 *)buf->buf + buf->readpos, len)) { CX18_DEBUG_WARN("copy %zd bytes to user failed for %s\n", len, s->name); return -EFAULT; } buf->readpos += len; if (s->type == CX18_ENC_STREAM_TYPE_MPG && buf != &cx->vbi.sliced_mpeg_buf) cx->mpg_data_received += len; return len; }