static void mainloop (void) { struct timeval timeout; vbi_capture_buffer *sliced_buffer; unsigned int n_frames; /* Don't wait more than two seconds for the driver to return data. */ timeout.tv_sec = 2; timeout.tv_usec = 0; /* Should receive a CNI within two seconds, call sign within ten seconds(?). */ if (services & VBI_SLICED_CAPTION_525) n_frames = 11 * 30; else n_frames = 3 * 25; for (; n_frames > 0; --n_frames) { unsigned int n_lines; int r; r = vbi_capture_pull (cap, /* raw_buffer */ NULL, &sliced_buffer, &timeout); switch (r) { case -1: fprintf (stderr, "VBI read error %d (%s)\n", errno, strerror (errno)); /* Could be ignored, esp. EIO with some drivers. */ exit (EXIT_FAILURE); case 0: fprintf (stderr, "VBI read timeout\n"); exit (EXIT_FAILURE); case 1: /* success */ break; default: assert (0); } n_lines = sliced_buffer->size / sizeof (vbi_sliced); vbi_decode (dec, (vbi_sliced *) sliced_buffer->data, n_lines, sliced_buffer->timestamp); if (quit) return; } printf ("No network ID received or network unknown.\n"); }
static void gst_teletextdec_process_telx_buffer (GstTeletextDec * teletext, GstBuffer * buf) { guint8 *data = GST_BUFFER_DATA (buf); const gint size = GST_BUFFER_SIZE (buf); guint offset = 0; gint res; teletext->in_timestamp = GST_BUFFER_TIMESTAMP (buf); teletext->in_duration = GST_BUFFER_DURATION (buf); if (teletext->frame == NULL) { gst_teletextdec_reset_frame (teletext); } while (offset < size) { res = gst_teletextdec_extract_data_units (teletext, teletext->frame, data, &offset, size); if (res == VBI_NEW_FRAME) { /* We have a new frame, it's time to feed the decoder */ vbi_sliced *s; gint n_lines; n_lines = teletext->frame->current_slice - teletext->frame->sliced_begin; GST_LOG_OBJECT (teletext, "Completed frame, decoding new %d lines", n_lines); s = g_memdup (teletext->frame->sliced_begin, n_lines * sizeof (vbi_sliced)); vbi_decode (teletext->decoder, s, n_lines, teletext->last_ts); /* From vbi_decode(): * timestamp shall advance by 1/30 to 1/25 seconds whenever calling this * function. Failure to do so will be interpreted as frame dropping, which * starts a resynchronization cycle, eventually a channel switch may be assumed * which resets even more decoder state. So even if a frame did not contain * any useful data this function must be called, with lines set to zero. */ teletext->last_ts += 0.04; g_free (s); gst_teletextdec_reset_frame (teletext); } else if (res == VBI_ERROR) { gst_teletextdec_reset_frame (teletext); return; } } return; }
static void cmd (unsigned int n) { vbi_sliced sliced; static double time = 0.0; sliced.id = VBI_SLICED_CAPTION_525; sliced.line = 21; sliced.data[0] = vbi_par8 (n >> 8); sliced.data[1] = vbi_par8 (n & 0x7F); vbi_decode (vbi, &sliced, 1, time); xevent (33333); time += 1 / 29.97; }
static void mainloop (void) { struct timeval timeout; /* Don't wait more than two seconds for the driver to return data. */ timeout.tv_sec = 2; timeout.tv_usec = 0; for (;;) { vbi_capture_buffer *sliced_buffer; unsigned int n_lines; int r; r = vbi_capture_pull (cap, /* raw_buffer */ NULL, &sliced_buffer, &timeout); switch (r) { case -1: fprintf (stderr, "VBI read error %d (%s)\n", errno, strerror (errno)); /* Could be ignored, esp. EIO with some drivers. */ exit (EXIT_FAILURE); case 0: fprintf (stderr, "VBI read timeout\n"); exit (EXIT_FAILURE); case 1: /* success */ break; default: assert (0); } n_lines = sliced_buffer->size / sizeof (vbi_sliced); vbi_decode (dec, (vbi_sliced *) sliced_buffer->data, n_lines, sliced_buffer->timestamp); } }
static vbi_bool decode_frame (const vbi_sliced * sliced, unsigned int n_lines, const uint8_t * raw, const vbi_sampling_par *sp, double sample_time, int64_t stream_time) { raw = raw; sp = sp; stream_time = stream_time; /* unused */ vbi_decode (vbi, sliced, n_lines, sample_time); /* xevent (1e6 / 30); */ return TRUE; }
static vbi_bool gst_teletextdec_convert (vbi_dvb_demux * dx, gpointer user_data, const vbi_sliced * sliced, guint n_lines, gint64 pts) { gdouble sample_time; vbi_sliced *s; GstTeletextDec *teletext = GST_TELETEXTDEC (user_data); GST_DEBUG_OBJECT (teletext, "Converting %u lines to decode", n_lines); sample_time = pts * (1 / 90000.0); s = g_memdup (sliced, n_lines * sizeof (vbi_sliced)); vbi_decode (teletext->decoder, s, n_lines, sample_time); g_free (s); return GST_FLOW_OK; }
int txt_render(int size, uint8_t *pdata) { const uint8_t *bp; int left; int lines; int64_t pts; vbi_sliced *psliced = txtdata->sliced; bp = pdata; left = size; if (txtdata) { while ( left > 0 ) { lines = vbi_dvb_demux_cor( txtdata->m_demuxer, psliced, SOFTSUB_SLICED_NB ,&pts, &bp, &left ); if ( lines > 0 ) { vbi_decode( txtdata->m_decoder, psliced, lines, pts/90000.0 ); } } } return 0; }
/***************************************************************************** * Decode: *****************************************************************************/ static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block ) { decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_block; subpicture_t *p_spu = NULL; video_format_t fmt; bool b_cached = false; vbi_page p_page; const uint8_t *p_pos; unsigned int i_left; if( (pp_block == NULL) || (*pp_block == NULL) ) return NULL; p_block = *pp_block; *pp_block = NULL; p_pos = p_block->p_buffer; i_left = p_block->i_buffer; while( i_left > 0 ) { vbi_sliced p_sliced[MAX_SLICES]; unsigned int i_lines = 0; int64_t i_pts; i_lines = vbi_dvb_demux_cor( p_sys->p_dvb_demux, p_sliced, MAX_SLICES, &i_pts, &p_pos, &i_left ); if( i_lines > 0 ) vbi_decode( p_sys->p_vbi_dec, p_sliced, i_lines, i_pts / 90000.0 ); } /* */ vlc_mutex_lock( &p_sys->lock ); const int i_align = p_sys->i_align; const unsigned int i_wanted_page = p_sys->i_wanted_page; const unsigned int i_wanted_subpage = p_sys->i_wanted_subpage; const bool b_opaque = p_sys->b_opaque; vlc_mutex_unlock( &p_sys->lock ); /* Try to see if the page we want is in the cache yet */ memset( &p_page, 0, sizeof(vbi_page) ); b_cached = vbi_fetch_vt_page( p_sys->p_vbi_dec, &p_page, vbi_dec2bcd( i_wanted_page ), i_wanted_subpage, VBI_WST_LEVEL_3p5, 25, true ); if( i_wanted_page == p_sys->i_last_page && !p_sys->b_update ) goto error; if( !b_cached ) { if( p_sys->i_last_page != i_wanted_page ) { /* We need to reset the subtitle */ p_spu = Subpicture( p_dec, &fmt, true, p_page.columns, p_page.rows, i_align, p_block->i_pts ); if( !p_spu ) goto error; p_spu->p_region->psz_text = strdup(""); p_sys->b_update = true; p_sys->i_last_page = i_wanted_page; goto exit; } goto error; } p_sys->b_update = false; p_sys->i_last_page = i_wanted_page; #ifdef ZVBI_DEBUG msg_Dbg( p_dec, "we now have page: %d ready for display", i_wanted_page ); #endif /* If there is a page or sub to render, then we do that here */ /* Create the subpicture unit */ p_spu = Subpicture( p_dec, &fmt, p_sys->b_text, p_page.columns, p_page.rows, i_align, p_block->i_pts ); if( !p_spu ) goto error; if( p_sys->b_text ) { unsigned int i_textsize = 7000; int i_total; char p_text[i_textsize+1]; i_total = vbi_print_page_region( &p_page, p_text, i_textsize, "UTF-8", 0, 0, 0, 0, p_page.columns, p_page.rows ); p_text[i_total] = '\0'; /* Strip off the pagenumber */ if( i_total <= 40 ) goto error; p_spu->p_region->psz_text = strdup( &p_text[8] ); #ifdef ZVBI_DEBUG msg_Info( p_dec, "page %x-%x(%d)\n%s", p_page.pgno, p_page.subno, i_total, p_text ); #endif } else { picture_t *p_pic = p_spu->p_region->p_picture; /* ZVBI is stupid enough to assume pitch == width */ p_pic->p->i_pitch = 4 * fmt.i_width; vbi_draw_vt_page( &p_page, ZVBI_PIXFMT_RGBA32, p_spu->p_region->p_picture->p->p_pixels, 1, 1 ); vlc_mutex_lock( &p_sys->lock ); memcpy( p_sys->nav_link, &p_page.nav_link, sizeof( p_sys->nav_link )) ; vlc_mutex_unlock( &p_sys->lock ); OpaquePage( p_pic, p_page, fmt, b_opaque ); } exit: vbi_unref_page( &p_page ); block_Release( p_block ); return p_spu; error: vbi_unref_page( &p_page ); if( p_spu != NULL ) { decoder_DeleteSubpicture( p_dec, p_spu ); p_spu = NULL; } block_Release( p_block ); return NULL; }
/***************************************************************************** * Decode: *****************************************************************************/ static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block ) { decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_block; subpicture_t *p_spu = NULL; video_format_t fmt; bool b_cached = false; vbi_page p_page; if( (pp_block == NULL) || (*pp_block == NULL) ) return NULL; p_block = *pp_block; *pp_block = NULL; if( p_block->i_buffer > 0 && ( ( p_block->p_buffer[0] >= 0x10 && p_block->p_buffer[0] <= 0x1f ) || ( p_block->p_buffer[0] >= 0x99 && p_block->p_buffer[0] <= 0x9b ) ) ) { vbi_sliced *p_sliced = p_sys->p_vbi_sliced; unsigned int i_lines = 0; p_block->i_buffer--; p_block->p_buffer++; while( p_block->i_buffer >= 2 ) { int i_id = p_block->p_buffer[0]; unsigned i_size = p_block->p_buffer[1]; if( 2 + i_size > p_block->i_buffer ) break; if( ( i_id == 0x02 || i_id == 0x03 ) && i_size >= 44 && i_lines < MAX_SLICES ) { if(p_block->p_buffer[3] == 0xE4 ) /* framing_code */ { unsigned line_offset = p_block->p_buffer[2] & 0x1f; unsigned field_parity = p_block->p_buffer[2] & 0x20; p_sliced[i_lines].id = VBI_SLICED_TELETEXT_B; if( line_offset > 0 ) p_sliced[i_lines].line = line_offset + (field_parity ? 0 : 313); else p_sliced[i_lines].line = 0; for( int i = 0; i < 42; i++ ) p_sliced[i_lines].data[i] = vbi_rev8( p_block->p_buffer[4 + i] ); i_lines++; } } p_block->i_buffer -= 2 + i_size; p_block->p_buffer += 2 + i_size; } if( i_lines > 0 ) vbi_decode( p_sys->p_vbi_dec, p_sliced, i_lines, 0 ); } /* */ vlc_mutex_lock( &p_sys->lock ); const int i_align = p_sys->i_align; const unsigned int i_wanted_page = p_sys->i_wanted_page; const unsigned int i_wanted_subpage = p_sys->i_wanted_subpage; const bool b_opaque = p_sys->b_opaque; vlc_mutex_unlock( &p_sys->lock ); /* Try to see if the page we want is in the cache yet */ memset( &p_page, 0, sizeof(vbi_page) ); b_cached = vbi_fetch_vt_page( p_sys->p_vbi_dec, &p_page, vbi_dec2bcd( i_wanted_page ), i_wanted_subpage, VBI_WST_LEVEL_3p5, 25, true ); if( i_wanted_page == p_sys->i_last_page && !p_sys->b_update ) goto error; if( !b_cached ) { if( p_sys->b_text && p_sys->i_last_page != i_wanted_page ) { /* We need to reset the subtitle */ p_spu = Subpicture( p_dec, &fmt, true, p_page.columns, p_page.rows, i_align, p_block->i_pts ); if( !p_spu ) goto error; subpicture_updater_sys_t *p_spu_sys = p_spu->updater.p_sys; p_spu_sys->text = strdup(""); p_sys->b_update = true; p_sys->i_last_page = i_wanted_page; goto exit; } goto error; } p_sys->b_update = false; p_sys->i_last_page = i_wanted_page; #ifdef ZVBI_DEBUG msg_Dbg( p_dec, "we now have page: %d ready for display", i_wanted_page ); #endif /* Ignore transparent rows at the beginning and end */ int i_first_row = get_first_visible_row( p_page.text, p_page.rows, p_page.columns ); int i_num_rows; if ( i_first_row < 0 ) { i_first_row = p_page.rows - 1; i_num_rows = 0; } else { i_num_rows = get_last_visible_row( p_page.text, p_page.rows, p_page.columns ) - i_first_row + 1; } #ifdef ZVBI_DEBUG msg_Dbg( p_dec, "After top and tail of page we have rows %i-%i of %i", i_first_row + 1, i_first_row + i_num_rows, p_page.rows ); #endif /* If there is a page or sub to render, then we do that here */ /* Create the subpicture unit */ p_spu = Subpicture( p_dec, &fmt, p_sys->b_text, p_page.columns, i_num_rows, i_align, p_block->i_pts ); if( !p_spu ) goto error; if( p_sys->b_text ) { unsigned int i_textsize = 7000; int i_total,offset; // char p_text[i_textsize+1]; char *p_text = (char *)malloc(i_textsize+1); // sunqueen modify i_total = vbi_print_page_region( &p_page, p_text, i_textsize, "UTF-8", 0, 0, 0, i_first_row, p_page.columns, i_num_rows ); for( offset=1; offset<i_total && isspace( p_text[i_total-offset ] ); offset++) p_text[i_total-offset] = '\0'; i_total -= offset; offset=0; while( offset < i_total && isspace( p_text[offset] ) ) offset++; subpicture_updater_sys_t *p_spu_sys = p_spu->updater.p_sys; p_spu_sys->text = strdup( &p_text[offset] ); p_spu_sys->align = i_align; p_spu_sys->i_font_height_percent = 5; p_spu_sys->renderbg = b_opaque; #ifdef ZVBI_DEBUG msg_Info( p_dec, "page %x-%x(%d)\n\"%s\"", p_page.pgno, p_page.subno, i_total, &p_text[offset] ); #endif free(p_text); // sunqueen add } else { picture_t *p_pic = p_spu->p_region->p_picture; /* ZVBI is stupid enough to assume pitch == width */ p_pic->p->i_pitch = 4 * fmt.i_width; /* Maintain subtitle postion */ p_spu->p_region->i_y = i_first_row*10; p_spu->i_original_picture_width = p_page.columns*12; p_spu->i_original_picture_height = p_page.rows*10; vbi_draw_vt_page_region( &p_page, ZVBI_PIXFMT_RGBA32, p_spu->p_region->p_picture->p->p_pixels, -1, 0, i_first_row, p_page.columns, i_num_rows, 1, 1); vlc_mutex_lock( &p_sys->lock ); memcpy( p_sys->nav_link, &p_page.nav_link, sizeof( p_sys->nav_link )) ; vlc_mutex_unlock( &p_sys->lock ); OpaquePage( p_pic, &p_page, fmt, b_opaque, i_first_row * p_page.columns ); } exit: vbi_unref_page( &p_page ); block_Release( p_block ); return p_spu; error: vbi_unref_page( &p_page ); if( p_spu != NULL ) { decoder_DeleteSubpicture( p_dec, p_spu ); p_spu = NULL; } block_Release( p_block ); return NULL; }
void VBIDecoder::decode(PES_packet& pes) { unsigned char* buf = pes.PES_packet_data; int len = pes.PES_packet_data_length; ScanlineMask mask; unsigned char* ptr = buf + 4; // assume we'll find magic cookie int i; vbi_sliced sliced_array[36]; vbi_sliced* sliced = sliced_array; vbi_sliced* sliced_end; // Look for one of the magic cookies identifying this buffer // as VBI data captured by the ivtv driver. if (memcmp(buf, "itv0", 4) == 0) { memcpy(&mask, ptr, 8); ptr += 8; } else if (memcmp(buf, "ITV0", 4) == 0) { mask.words[0] = 0xffffffff; mask.words[1] = 0xf; } else return; if (verbose > 1) fprintf(fplog, "VBI: time=%.4f len=%d mask=%#llx\n", (double)currTimestamp, len, (unsigned long long)mask.llword); for (i = 0; i < 36; i++) { if (FD_ISSET(i, &mask.bits)) { // We'll adjust the value of line later when we know the type sliced->line = i; sliced++; FD_CLR(i, &mask.bits); } // Optimization, skip to next word when this word is zero if (i < 32 && mask.words[0] == 0) i = 31; if (i >= 32 && mask.words[1] == 0) break; } sliced_end = sliced; sliced = sliced_array; for (unsigned char* end = buf + len; ptr+43 <= end; ptr += 43, sliced++) { if (sliced == sliced_end) { if (verbose > 1) fprintf(fplog, "Have more scanlines than bits in mask!\n"); break; } int type = *ptr; // If line is < 18, it must be a field 1 scanline, just add 6 // Otherwise, it depends on ivtv type if (sliced->line < 18) sliced->line += 6; else { if (type == IVTV_SLICED_TYPE_CC) // assume NTSC 525 scanlines { // 263 = 525/2+1 sliced->line += (263-18+6); } else // assume PAL 625 scanlines { // 313 = 625/2+1 sliced->line += (313-18+6); } } // set sliced->id based on type switch (type) { // Teletext (uses lines 6-22 for PAL) case IVTV_SLICED_TYPE_TELETEXT: sliced->id = VBI_SLICED_TELETEXT_B; break; // Closed Captions (line 21 NTSC) case IVTV_SLICED_TYPE_CC: sliced->id = VBI_SLICED_CAPTION_525; break; // Wide Screen Signal (line 23 PAL) case IVTV_SLICED_TYPE_WSS: sliced->id = VBI_SLICED_WSS_625; // VBI_SLICED_WSS_CPR1204? break; // Video Programming System (PAL) (line 16) case IVTV_SLICED_TYPE_VPS: sliced->id = VBI_SLICED_VPS; break; } // Copy the ivtv data to the vbi_sliced structure memcpy(sliced->data, ptr+1, 42); if (verbose > 1) { fprintf(fplog, " ivtv-type=%#x line=%d zvbi-id=%#x", type, sliced->line, sliced->id); unsigned char* p = ptr+1; int n = (type == IVTV_SLICED_TYPE_CC) ? 2 : 42; for (i = 0; i < n; i++, p++) { fprintf(fplog, " %02x", *p); int c = (*p) & 0x7f; if (0x20 <= c && c <= 0x7f) fprintf(fplog, "(%c)", c); } putc('\n', fplog); } } if (verbose && sliced != sliced_end) { fprintf(fplog, "Have fewer scanlines than bits in mask!\n"); } if (skipVBI > 0) { if (verbose) fprintf(fplog, "Skip\n"); skipVBI--; return; } if (verbose > 1) fflush(fplog); // vbi_decode is very fussy about timestamps // if the difference between the previous time and the current time // is less than 0.025or greater than 0.050, it will blank the page // To keep it happy we give it timestamps that won't cause it // to ignore valid data just because the timestamps provided by // the ivtv driver don't quite match its expectations. decoderTimestamp += 0.03; vbi_decode(decoder, sliced_array, sliced - sliced_array, decoderTimestamp); }
/***************************************************************************** * Decode: *****************************************************************************/ static int Decode( decoder_t *p_dec, block_t *p_block ) { decoder_sys_t *p_sys = p_dec->p_sys; subpicture_t *p_spu = NULL; video_format_t fmt; bool b_cached = false; vbi_page p_page; if( p_block == NULL ) /* No Drain */ return VLCDEC_SUCCESS; if( p_block->i_buffer > 0 && ( ( p_block->p_buffer[0] >= 0x10 && p_block->p_buffer[0] <= 0x1f ) || ( p_block->p_buffer[0] >= 0x99 && p_block->p_buffer[0] <= 0x9b ) ) ) { vbi_sliced *p_sliced = p_sys->p_vbi_sliced; unsigned int i_lines = 0; p_block->i_buffer--; p_block->p_buffer++; while( p_block->i_buffer >= 2 ) { int i_id = p_block->p_buffer[0]; unsigned i_size = p_block->p_buffer[1]; if( 2 + i_size > p_block->i_buffer ) break; if( ( i_id == 0x02 || i_id == 0x03 ) && i_size >= 44 && i_lines < MAX_SLICES ) { if(p_block->p_buffer[3] == 0xE4 ) /* framing_code */ { unsigned line_offset = p_block->p_buffer[2] & 0x1f; unsigned field_parity = p_block->p_buffer[2] & 0x20; p_sliced[i_lines].id = VBI_SLICED_TELETEXT_B; if( line_offset > 0 ) p_sliced[i_lines].line = line_offset + (field_parity ? 0 : 313); else p_sliced[i_lines].line = 0; for( int i = 0; i < 42; i++ ) p_sliced[i_lines].data[i] = vbi_rev8( p_block->p_buffer[4 + i] ); i_lines++; } } p_block->i_buffer -= 2 + i_size; p_block->p_buffer += 2 + i_size; } if( i_lines > 0 ) vbi_decode( p_sys->p_vbi_dec, p_sliced, i_lines, 0 ); } /* */ vlc_mutex_lock( &p_sys->lock ); const int i_align = p_sys->i_align; const unsigned int i_wanted_page = p_sys->i_wanted_page; const unsigned int i_wanted_subpage = p_sys->i_wanted_subpage; const bool b_opaque = p_sys->b_opaque; const unsigned int i_level = p_sys->i_level > 3 ? 3 : p_sys->i_level; vlc_mutex_unlock( &p_sys->lock ); /* Try to see if the page we want is in the cache yet */ memset( &p_page, 0, sizeof(vbi_page) ); b_cached = vbi_fetch_vt_page( p_sys->p_vbi_dec, &p_page, vbi_dec2bcd( i_wanted_page ), i_wanted_subpage, level_zvbi_values[i_level], 25, true ); if( i_wanted_page == p_sys->i_last_page && !p_sys->b_update ) goto error; if( !b_cached ) { if( p_sys->b_text && p_sys->i_last_page != i_wanted_page ) { /* We need to reset the subtitle */ p_spu = Subpicture( p_dec, &fmt, true, p_page.columns, p_page.rows, i_align, p_block->i_pts ); if( !p_spu ) goto error; subpicture_updater_sys_t *p_spu_sys = p_spu->updater.p_sys; p_spu_sys->region.p_segments = text_segment_New(""); p_sys->b_update = true; p_sys->i_last_page = i_wanted_page; goto exit; } goto error; } p_sys->b_update = false; p_sys->i_last_page = i_wanted_page; #ifdef ZVBI_DEBUG msg_Dbg( p_dec, "we now have page: %d ready for display", i_wanted_page ); #endif /* Ignore transparent rows at the beginning and end */ int i_first_row = get_first_visible_row( p_page.text, p_page.rows, p_page.columns ); int i_num_rows; if ( i_first_row < 0 ) { i_first_row = p_page.rows - 1; i_num_rows = 0; } else { i_num_rows = get_last_visible_row( p_page.text, p_page.rows, p_page.columns ) - i_first_row + 1; } #ifdef ZVBI_DEBUG msg_Dbg( p_dec, "After top and tail of page we have rows %i-%i of %i", i_first_row + 1, i_first_row + i_num_rows, p_page.rows ); #endif /* If there is a page or sub to render, then we do that here */ /* Create the subpicture unit */ p_spu = Subpicture( p_dec, &fmt, p_sys->b_text, p_page.columns, i_num_rows, i_align, p_block->i_pts ); if( !p_spu ) goto error; if( p_sys->b_text ) { unsigned int i_textsize = 7000; int i_total,offset; char p_text[i_textsize+1]; i_total = vbi_print_page_region( &p_page, p_text, i_textsize, "UTF-8", 0, 0, 0, i_first_row, p_page.columns, i_num_rows ); for( offset=1; offset<i_total && isspace( p_text[i_total-offset ] ); offset++) p_text[i_total-offset] = '\0'; i_total -= offset; offset=0; while( offset < i_total && isspace( p_text[offset] ) ) offset++; subpicture_updater_sys_t *p_spu_sys = p_spu->updater.p_sys; p_spu_sys->region.p_segments = text_segment_New( &p_text[offset] ); if( p_spu_sys->region.p_segments && b_opaque ) { p_spu_sys->region.p_segments->style = text_style_Create( STYLE_NO_DEFAULTS ); if( p_spu_sys->region.p_segments->style ) { /* Set text background */ p_spu_sys->region.p_segments->style->i_style_flags = STYLE_BACKGROUND; p_spu_sys->region.p_segments->style->i_features |= STYLE_HAS_FLAGS; } } p_spu_sys->region.inner_align = i_align; p_spu_sys->region.flags = UPDT_REGION_IGNORE_BACKGROUND; #ifdef ZVBI_DEBUG msg_Info( p_dec, "page %x-%x(%d)\n\"%s\"", p_page.pgno, p_page.subno, i_total, &p_text[offset] ); #endif } else { picture_t *p_pic = p_spu->p_region->p_picture; /* ZVBI is stupid enough to assume pitch == width */ p_pic->p->i_pitch = 4 * fmt.i_width; /* Maintain subtitle postion */ p_spu->p_region->i_y = i_first_row*10; p_spu->i_original_picture_width = p_page.columns*12; p_spu->i_original_picture_height = p_page.rows*10; vbi_draw_vt_page_region( &p_page, ZVBI_PIXFMT_RGBA32, p_spu->p_region->p_picture->p->p_pixels, -1, 0, i_first_row, p_page.columns, i_num_rows, 1, 1); vlc_mutex_lock( &p_sys->lock ); memcpy( p_sys->nav_link, &p_page.nav_link, sizeof( p_sys->nav_link )) ; vlc_mutex_unlock( &p_sys->lock ); OpaquePage( p_pic, &p_page, fmt, b_opaque, i_first_row * p_page.columns ); } exit: vbi_unref_page( &p_page ); block_Release( p_block ); if( p_spu ) decoder_QueueSub( p_dec, p_spu ); return VLCDEC_SUCCESS; error: vbi_unref_page( &p_page ); block_Release( p_block ); return VLCDEC_SUCCESS; }
/***************************************************************************** * Decode: *****************************************************************************/ static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block ) { decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_block; subpicture_t *p_spu = NULL; video_format_t fmt; bool b_cached = false; vbi_page p_page; if( (pp_block == NULL) || (*pp_block == NULL) ) return NULL; p_block = *pp_block; *pp_block = NULL; if( p_block->i_buffer > 0 && ( ( p_block->p_buffer[0] >= 0x10 && p_block->p_buffer[0] <= 0x1f ) || ( p_block->p_buffer[0] >= 0x99 && p_block->p_buffer[0] <= 0x9b ) ) ) { vbi_sliced *p_sliced = p_sys->p_vbi_sliced; unsigned int i_lines = 0; p_block->i_buffer--; p_block->p_buffer++; while( p_block->i_buffer >= 2 ) { int i_id = p_block->p_buffer[0]; unsigned i_size = p_block->p_buffer[1]; if( 2 + i_size > p_block->i_buffer ) break; if( ( i_id == 0x02 || i_id == 0x03 ) && i_size >= 44 && i_lines < MAX_SLICES ) { unsigned line_offset = p_block->p_buffer[2] & 0x1f; unsigned field_parity = p_block->p_buffer[2] & 0x20; p_sliced[i_lines].id = VBI_SLICED_TELETEXT_B; if( line_offset > 0 ) p_sliced[i_lines].line = line_offset + (field_parity ? 0 : 313); else p_sliced[i_lines].line = 0; for( int i = 0; i < 42; i++ ) p_sliced[i_lines].data[i] = vbi_rev8( p_block->p_buffer[4 + i] ); i_lines++; } p_block->i_buffer -= 2 + i_size; p_block->p_buffer += 2 + i_size; } if( i_lines > 0 ) vbi_decode( p_sys->p_vbi_dec, p_sliced, i_lines, (double)p_block->i_pts / 1000000 ); } /* */ vlc_mutex_lock( &p_sys->lock ); const int i_align = p_sys->i_align; const unsigned int i_wanted_page = p_sys->i_wanted_page; const unsigned int i_wanted_subpage = p_sys->i_wanted_subpage; const bool b_opaque = p_sys->b_opaque; vlc_mutex_unlock( &p_sys->lock ); /* Try to see if the page we want is in the cache yet */ memset( &p_page, 0, sizeof(vbi_page) ); b_cached = vbi_fetch_vt_page( p_sys->p_vbi_dec, &p_page, vbi_dec2bcd( i_wanted_page ), i_wanted_subpage, VBI_WST_LEVEL_3p5, 25, true ); if( i_wanted_page == p_sys->i_last_page && !p_sys->b_update ) goto error; if( !b_cached ) { if( p_sys->i_last_page != i_wanted_page ) { /* We need to reset the subtitle */ p_spu = Subpicture( p_dec, &fmt, true, p_page.columns, p_page.rows, i_align, p_block->i_pts ); if( !p_spu ) goto error; p_spu->p_region->psz_text = strdup(""); p_sys->b_update = true; p_sys->i_last_page = i_wanted_page; goto exit; } goto error; } p_sys->b_update = false; p_sys->i_last_page = i_wanted_page; #ifdef ZVBI_DEBUG msg_Dbg( p_dec, "we now have page: %d ready for display", i_wanted_page ); #endif /* If there is a page or sub to render, then we do that here */ /* Create the subpicture unit */ p_spu = Subpicture( p_dec, &fmt, p_sys->b_text, p_page.columns, p_page.rows, i_align, p_block->i_pts ); if( !p_spu ) goto error; if( p_sys->b_text ) { unsigned int i_textsize = 7000; int i_total; char p_text[i_textsize+1]; i_total = vbi_print_page_region( &p_page, p_text, i_textsize, "UTF-8", 0, 0, 0, 0, p_page.columns, p_page.rows ); p_text[i_total] = '\0'; /* Strip off the pagenumber */ if( i_total <= 40 ) goto error; p_spu->p_region->psz_text = strdup( &p_text[8] ); #ifdef ZVBI_DEBUG msg_Info( p_dec, "page %x-%x(%d)\n%s", p_page.pgno, p_page.subno, i_total, p_text ); #endif } else { picture_t *p_pic = p_spu->p_region->p_picture; /* ZVBI is stupid enough to assume pitch == width */ p_pic->p->i_pitch = 4 * fmt.i_width; vbi_draw_vt_page( &p_page, ZVBI_PIXFMT_RGBA32, p_spu->p_region->p_picture->p->p_pixels, 1, 1 ); vlc_mutex_lock( &p_sys->lock ); memcpy( p_sys->nav_link, &p_page.nav_link, sizeof( p_sys->nav_link )) ; vlc_mutex_unlock( &p_sys->lock ); OpaquePage( p_pic, p_page, fmt, b_opaque ); } exit: vbi_unref_page( &p_page ); block_Release( p_block ); return p_spu; error: vbi_unref_page( &p_page ); if( p_spu != NULL ) { decoder_DeleteSubpicture( p_dec, p_spu ); p_spu = NULL; } block_Release( p_block ); return NULL; }