コード例 #1
0
void add_current_pts(struct ccx_common_timing_ctx *ctx, LLONG pts)
{
	set_current_pts(ctx, ctx->current_pts + pts);
}
コード例 #2
0
ファイル: wtv_functions.c プロジェクト: afeldspar/ccextractor
LLONG get_data(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb, struct demuxer_data *data)
{
	static int video_streams[32];
	static int alt_stream; //Stream to use for timestamps if the cc stream has broken timestamps
	static int use_alt_stream = 0;
	static int num_streams = 0;
	struct lib_cc_decode *dec_ctx = update_decoder_list(ctx);

	while(1)
	{
		int bytesread = 0;
		// Read the 32 bytes containing the GUID and length and stream_id info
		get_sized_buffer(ctx->demux_ctx, cb, 32);
		if(cb->buffer == NULL)
			return CCX_EOF;

		uint8_t guid[16];
		memcpy(&guid, cb->buffer, 16); // Read the GUID
		int x;
		for(x=0; x<16; x++)
			dbg_print(CCX_DMT_PARSE, "%02X ", guid[x]);
		dbg_print(CCX_DMT_PARSE, "\n");
		uint32_t len;
		memcpy(&len, cb->buffer+16, 4); // Read the length
		len-=32;
		dbg_print(CCX_DMT_PARSE, "len %X\n", len);
		uint32_t pad;
		pad = len%8==0 ? 0 : 8- (len % 8);  // Calculate the padding to add to the length
		// to get to the next GUID
		dbg_print(CCX_DMT_PARSE, "pad %X\n", pad);
		uint32_t stream_id;
		memcpy(&stream_id, cb->buffer+20, 4);
		stream_id = stream_id & 0x7f;       // Read and calculate the stream_id
		dbg_print(CCX_DMT_PARSE, "stream_id: 0x%X\n", stream_id);

		for(x=0; x<num_streams; x++)
			dbg_print(CCX_DMT_PARSE, "video stream_id: %X\n", video_streams[x]);
		if( !memcmp(guid, WTV_EOF, 16 ))
		{
			// This is the end of the data in this file
			// read the padding at the end of the file
			// and return one more byte
			dbg_print(CCX_DMT_PARSE, "WTV EOF\n");
			uint8_t *parsebuf;
			parsebuf = (uint8_t*)malloc(1024);
			do {
				buffered_read(ctx->demux_ctx, parsebuf, 1024);
				ctx->demux_ctx->past+=1024;
			} while (result==1024);
			ctx->demux_ctx->past+=result;
			free(parsebuf);
			free(cb->buffer);
			cb->buffer=NULL;
			//return one more byte so the final percentage is shown correctly
			*(data->buffer+data->len)=0x00;
			data->len++;
			return CCX_EOF;
		}
		if( !memcmp(guid, WTV_STREAM2, 16 ) )
		{
			// The WTV_STREAM2 GUID appares near the start of the data dir
			// It maps stream_ids to the type of stream
			dbg_print(CCX_DMT_PARSE, "WTV STREAM2\n");
			get_sized_buffer(ctx->demux_ctx, cb, 0xc+16);
			if(cb->buffer==NULL)
				return CCX_EOF;
			static unsigned char stream_type[16];
			memcpy(&stream_type, cb->buffer+0xc, 16); //Read the stream type GUID
			const void *stream_guid;
			if(ccx_options.wtvmpeg2)
				stream_guid = WTV_STREAM_VIDEO; // We want mpeg2 data if the user set -wtvmpeg2
			else
				stream_guid = WTV_STREAM_MSTVCAPTION; // Otherwise we want the MSTV captions stream
			if(!memcmp(stream_type, stream_guid, 16 ) )
			{
				video_streams[num_streams]=stream_id; // We keep a list of stream ids
				num_streams++;                        // Even though there should only be 1
			}
			if (memcmp(stream_type, WTV_STREAM_AUDIO, 16))
				alt_stream = stream_id;
			len-=28;
		}
		if (!memcmp(guid, WTV_TIMING, 16) && ((use_alt_stream < WTV_CC_TIMESTAMP_MAGIC_THRESH && check_stream_id(stream_id, video_streams, num_streams))
					|| (use_alt_stream == WTV_CC_TIMESTAMP_MAGIC_THRESH && stream_id == alt_stream)))
		{
			// The WTV_TIMING GUID contains a timestamp for the given stream_id
			dbg_print(CCX_DMT_PARSE, "WTV TIMING\n");
			get_sized_buffer(ctx->demux_ctx, cb, 0x8+0x8);
			if(cb->buffer==NULL)
				return CCX_EOF;
			int64_t time;
			memcpy(&time, cb->buffer+0x8, 8); // Read the timestamp
			dbg_print(CCX_DMT_PARSE, "TIME: %ld\n", time);
			if (time != -1 && time != WTV_CC_TIMESTAMP_MAGIC) { // Ignore -1 timestamps
				set_current_pts(dec_ctx->timing, time_to_pes_time(time));
				frames_since_ref_time = 0;
				set_fts(dec_ctx->timing);
			}
			else if (time == WTV_CC_TIMESTAMP_MAGIC && stream_id != alt_stream) {
				use_alt_stream++;
				mprint("WARNING: %i WTV_CC_TIMESTAMP_MAGIC detected in cc timestamps. \n", use_alt_stream);
				if (use_alt_stream == WTV_CC_TIMESTAMP_MAGIC_THRESH)
					mprint("WARNING: WTV_CC_TIMESTAMP_MAGIC_THRESH reached. Switching to alt timestamps!\n");
			}
			len-=16;
		}
		if( !memcmp(guid, WTV_DATA, 16 )
				&& check_stream_id(stream_id, video_streams, num_streams) && dec_ctx->timing->current_pts != 0
				&& (ccx_options.wtvmpeg2 || (!ccx_options.wtvmpeg2 && len==2)))
		{
			// This is the data for a stream we want to process
			dbg_print(CCX_DMT_PARSE, "\nWTV DATA\n");
			get_sized_buffer(ctx->demux_ctx, cb, len);
			if(cb->buffer==NULL)
				return CCX_EOF;
			memcpy(data->buffer+data->len, cb->buffer, len);
			data->len+=result;
			bytesread+=(int) len;
			frames_since_ref_time++;
			set_fts(dec_ctx->timing);
			if(pad>0)
			{ //Make sure we skip any padding too, since we are returning here
				skip_sized_buffer(ctx->demux_ctx, cb, pad);
			}
			return bytesread;
		}
		if(len+pad>0)
		{
			// skip any remaining data
			// For any unhandled GUIDs this will be len+pad
			// For others it will just be pad
			skip_sized_buffer(ctx->demux_ctx, cb, len+pad);
		}
	}
}
コード例 #3
0
// Return TRUE if the data parsing finished, FALSE otherwise.
// estream->pos is advanced. Data is only processed if esstream->error
// is FALSE, parsing can set esstream->error to TRUE.
static int gop_header(struct lib_cc_decode *ctx, struct bitstream *esstream, struct cc_subtitle *sub)
{
	debug("GOP header\n");

	if (esstream->error || esstream->bitsleft <= 0)
		return 0;

	// We only get here after seeing that start code
	if (read_u32(esstream) != 0xB8010000) // LSB first (0x000001B8)
		fatal(CCX_COMMON_EXIT_BUG_BUG, "gop_header: read_u32(esstream) != 0xB8010000. Please file a bug report in GitHub.\n");

	unsigned drop_frame_flag = (unsigned) read_bits(esstream,1);
	struct gop_time_code gtc;
	gtc.time_code_hours = (int) read_bits(esstream,5);
	gtc.time_code_minutes = (int) read_bits(esstream,6);
	skip_bits(esstream,1); // Marker bit
	gtc.time_code_seconds = (int) read_bits(esstream,6);
	gtc.time_code_pictures = (int) read_bits(esstream,6);
	gtc.inited = 1;
	calculate_ms_gop_time(&gtc);

	if (esstream->bitsleft < 0)
		return 0;

	if (gop_accepted(&gtc))
	{
		// Do GOP padding during GOP header. The previous GOP and all
		// included captions are written. Use the current GOP time to
		// do the padding.

		// Flush buffered cc blocks before doing the housekeeping
		if (ctx->has_ccdata_buffered)
		{
			process_hdcc(ctx, sub);
		}

		// Last GOPs pulldown frames
		if ((ctx->current_pulldownfields>0) != (ctx->pulldownfields>0))
		{
			ctx->current_pulldownfields = ctx->pulldownfields;
			debug("Pulldown: %s", (ctx->pulldownfields ? "on" : "off"));
			if (ctx->pulldownfields)
				debug(" - %u fields in last GOP", ctx->pulldownfields);
			debug("\n");
		}
		ctx->pulldownfields = 0;

		// Report synchronization jumps between GOPs. Warn if there
		// are 20% or more deviation.
		if ( (ccx_options.debug_mask & CCX_DMT_TIME)
				&& ((gtc.ms - gop_time.ms // more than 20% longer
						> ctx->frames_since_last_gop*1000.0/current_fps*1.2)
					||
					(gtc.ms - gop_time.ms // or 20% shorter
					 < ctx->frames_since_last_gop*1000.0/current_fps*0.8))
				&& first_gop_time.inited )
		{
			mprint("\rWarning: Jump in GOP timing.\n");
			mprint("  (old) %s",
					print_mstime_static(gop_time.ms));
			mprint("  +  %s (%uF)",
					print_mstime_static((LLONG) (ctx->frames_since_last_gop
							*1000.0/current_fps)),
					ctx->frames_since_last_gop);
			mprint("  !=  (new) %s\n",
					print_mstime_static(gtc.ms));
		}

		if (first_gop_time.inited == 0)
		{
			first_gop_time = gtc;

			// It needs to be "+1" because the frame count starts at 0 and we
			// need the length of all frames.
			if ( total_frames_count == 0 )
			{   // If this is the first frame there cannot be an offset
				ctx->timing->fts_fc_offset = 0;
				// first_gop_time.ms stays unchanged
			}
			else
			{
				ctx->timing->fts_fc_offset = (LLONG) ((total_frames_count+1)
						*1000.0/current_fps);
				// Compensate for those written before
				first_gop_time.ms -= ctx->timing->fts_fc_offset;
			}

			dbg_print(CCX_DMT_TIME, "\nFirst GOP time: %02u:%02u:%02u:%03u %+lldms\n",
					gtc.time_code_hours,
					gtc.time_code_minutes, gtc.time_code_seconds,
					(unsigned) (1000.0*gtc.time_code_pictures/current_fps),
					ctx->timing->fts_fc_offset);
		}

		gop_time = gtc;

		ctx->frames_since_last_gop=0;
		// Indicate that we read a gop header (since last frame number 0)
		ctx->saw_gop_header = 1;

		// If we use GOP timing, reconstruct the PTS from the GOP
		if (ccx_options.use_gop_as_pts==1)
		{
			set_current_pts(ctx->timing, gtc.ms*(MPEG_CLOCK_FREQ/1000));
			ctx->timing->current_tref = 0;
			frames_since_ref_time = 0;
			set_fts(ctx->timing);
			fts_at_gop_start = get_fts_max(ctx->timing);
		}
		else
		{
			// FIXME: Wrong when PTS are not increasing but are identical
			// troughout the GOP and then jump to the next time for the
			// next GOP.
			// This effect will also lead to captions being one GOP early
			// for DVD captions.
			fts_at_gop_start = get_fts_max(ctx->timing) + (LLONG) (1000.0/current_fps);
		}

		if (ccx_options.debug_mask & CCX_DMT_TIME)
		{
			dbg_print(CCX_DMT_TIME, "\nNew GOP:\n");
			dbg_print(CCX_DMT_TIME, "\nDrop frame flag: %u:\n", drop_frame_flag);
			print_debug_timing(ctx->timing);
		}
	}

	return 1;
}