static u32 iso_progressive_read_thread(void *param) { ISOProgressiveReader *reader = (ISOProgressiveReader *)param; u32 track_number; GF_ISOSample *iso_sample; u32 samples_processed; u32 sample_index; u32 sample_count; samples_processed = 0; sample_count = 0; track_number = 0; /* samples are numbered starting from 1 */ sample_index = 1; while (reader->do_run == GF_TRUE) { /* we can only parse if there is a movie */ if (reader->movie) { /* block the data input until we are done in the parsing */ gf_mx_p(reader->mutex); /* get the track number we want */ if (track_number == 0) { track_number = gf_isom_get_track_by_id(reader->movie, reader->track_id); } /* only if we have the track number can we try to get the sample data */ if (track_number != 0) { u32 new_sample_count; u32 di; /*descriptor index*/ /* let's see how many samples we have since the last parsed */ new_sample_count = gf_isom_get_sample_count(reader->movie, track_number); if (new_sample_count > sample_count) { /* New samples have been added to the file */ fprintf(stdout, "Found %d new samples (total: %d)\n", new_sample_count - sample_count, new_sample_count); if (sample_count == 0) { sample_count = new_sample_count; } } if (sample_count == 0) { /*let the reader push new data */ gf_mx_v(reader->mutex); //gf_sleep(1000); } else { /* let's analyze the samples we have parsed so far one by one */ iso_sample = gf_isom_get_sample(reader->movie, track_number, sample_index, &di); if (iso_sample) { /* if you want the sample description data, you can call: GF_Descriptor *desc = gf_isom_get_decoder_config(reader->movie, reader->track_handle, di); */ samples_processed++; /*here we dump some sample info: samp->data, samp->dataLength, samp->isRAP, samp->DTS, samp->CTS_Offset */ fprintf(stdout, "Found sample #%5d (#%5d) of length %8d, RAP: %d, DTS: "LLD", CTS: "LLD"\r", sample_index, samples_processed, iso_sample->dataLength, iso_sample->IsRAP, iso_sample->DTS, iso_sample->DTS+iso_sample->CTS_Offset); sample_index++; /*release the sample data, once you're done with it*/ gf_isom_sample_del(&iso_sample); /* once we have read all the samples, we can release some data and force a reparse of the input buffer */ if (sample_index > sample_count) { u64 new_buffer_start; u64 missing_bytes; fprintf(stdout, "\nReleasing unnecessary buffers\n"); /* release internal structures associated with the samples read so far */ gf_isom_reset_tables(reader->movie, GF_TRUE); #if 1 /* release the associated input data as well */ gf_isom_reset_data_offset(reader->movie, &new_buffer_start); if (new_buffer_start) { u32 offset = (u32)new_buffer_start; memmove(reader->data, reader->data+offset, reader->data_size-offset); reader->valid_data_size -= offset; } sprintf(reader->data_url, "gmem://%d@%p", reader->valid_data_size, reader->data); gf_isom_refresh_fragmented(reader->movie, &missing_bytes, reader->data_url); #endif /* update the sample count and sample index */ sample_count = new_sample_count - sample_count; assert(sample_count == 0); sample_index = 1; } } else { GF_Err e = gf_isom_last_error(reader->movie); fprintf(stdout, "Could not get sample %s\r", gf_error_to_string(e)); } /* and finally, let the data reader push more data */ gf_mx_v(reader->mutex); } } } else { //gf_sleep(1); } } return 0; }
void isor_net_io(void *cbk, GF_NETIO_Parameter *param) { GF_Err e; u32 size = 0; char *local_name; ISOMReader *read = (ISOMReader *) cbk; /*handle service message*/ if (!read->buffering) gf_service_download_update_stats(read->dnload); if (param->msg_type==GF_NETIO_DATA_TRANSFERED) { e = GF_EOS; } else if (param->msg_type==GF_NETIO_DATA_EXCHANGE) { e = GF_OK; size = param->size; } else { e = param->error; } if (e<GF_OK) { /*error opening service*/ if (!read->mov) { /* if there is an intermediate between this module and the terminal, report to it */ if (read->input->query_proxy && read->input->proxy_udta && read->input->proxy_type) { send_proxy_command(read, GF_FALSE, GF_FALSE, e, NULL, NULL); } else { gf_service_connect_ack(read->service, NULL, e); } } return; } /*open file if not done yet (bad interleaving)*/ if (e==GF_EOS) { const char *local_name; if (read->mov) return; local_name = gf_dm_sess_get_cache_name(read->dnload); if (!local_name) { if (read->input->query_proxy && read->input->proxy_udta && read->input->proxy_type) { send_proxy_command(read, GF_FALSE, GF_FALSE, GF_SERVICE_ERROR, NULL, NULL); } else { gf_service_connect_ack(read->service, NULL, GF_SERVICE_ERROR); } return; } e = GF_OK; read->mov = gf_isom_open(local_name, GF_ISOM_OPEN_READ, NULL); if (!read->mov) e = gf_isom_last_error(NULL); else read->time_scale = gf_isom_get_timescale(read->mov); read->frag_type = gf_isom_is_fragmented(read->mov) ? 1 : 0; if (read->input->query_proxy && read->input->proxy_udta && read->input->proxy_type) { send_proxy_command(read, GF_FALSE, GF_FALSE, GF_OK, NULL, NULL); } else { gf_service_connect_ack(read->service, NULL, GF_OK); } if (read->no_service_desc) isor_declare_objects(read); } if (!size) return; /*service is opened, nothing to do*/ if (read->mov) { isor_check_buffer_level(read); /*end of chunk*/ if (read->frag_type && (param->reply==1) ) { u64 bytesMissing = 0; gf_mx_p(read->segment_mutex); e = gf_isom_refresh_fragmented(read->mov, &bytesMissing, NULL); gf_mx_v(read->segment_mutex); } return; } /*try to open the service*/ local_name = (char *)gf_dm_sess_get_cache_name(read->dnload); if (!local_name) { if (read->input->query_proxy && read->input->proxy_udta && read->input->proxy_type) { send_proxy_command(read, GF_FALSE, GF_FALSE, GF_SERVICE_ERROR, NULL, NULL); } else { gf_service_connect_ack(read->service, NULL, GF_SERVICE_ERROR); } return; } /*not enogh data yet*/ if (read->missing_bytes && (read->missing_bytes > size) ) { read->missing_bytes -= size; return; } e = gf_isom_open_progressive(local_name, 0, 0, &read->mov, &read->missing_bytes); switch (e) { case GF_ISOM_INCOMPLETE_FILE: return; case GF_OK: break; default: if (read->input->query_proxy && read->input->proxy_udta && read->input->proxy_type) { send_proxy_command(read, GF_FALSE, GF_FALSE, e, NULL, NULL); } else { gf_service_connect_ack(read->service, NULL, e); } return; } read->frag_type = gf_isom_is_fragmented(read->mov) ? 1 : 0; /*ok let's go, we can setup the decoders */ read->time_scale = gf_isom_get_timescale(read->mov); if (read->input->query_proxy && read->input->proxy_udta && read->input->proxy_type) { send_proxy_command(read, GF_FALSE, GF_FALSE, GF_OK, NULL, NULL); } else { gf_service_connect_ack(read->service, NULL, GF_OK); } if (read->no_service_desc) isor_declare_objects(read); }
int main(int argc, char **argv) { /* The ISO progressive reader */ ISOProgressiveReader reader; /* Error indicator */ GF_Err e; /* input file to be read in the data buffer */ FILE *input; /* number of bytes read from the file at each read operation */ u32 read_bytes; /* number of bytes read from the file (total) */ u64 total_read_bytes; /* size of the input file */ u64 file_size; /* number of bytes required to finish the current ISO Box reading (not used here)*/ u64 missing_bytes; /* Thread used to run the ISO parsing in */ GF_Thread *reading_thread; /* Return value for the program */ int ret = 0; /* Usage */ if (argc != 2) { fprintf(stdout, "Usage: %s filename\n", argv[0]); return 1; } /* Initializing GPAC framework */ /* Enables GPAC memory tracking in debug mode only */ #if defined(DEBUG) || defined(_DEBUG) gf_sys_init(GF_MemTrackerSimple); gf_log_set_tool_level(GF_LOG_ALL, GF_LOG_WARNING); gf_log_set_tool_level(GF_LOG_MEMORY, GF_LOG_INFO); #else gf_sys_init(GF_MemTrackerNone); gf_log_set_tool_level(GF_LOG_ALL, GF_LOG_WARNING); #endif /* This is an input file to read data from. Could be replaced by any other method to retrieve the data (e.g. JavaScript, socket, ...)*/ input = gf_fopen(argv[1], "rb"); if (!input) { fprintf(stdout, "Could not open file %s for reading.\n", argv[1]); gf_sys_close(); return 1; } gf_fseek(input, 0, SEEK_END); file_size = gf_ftell(input); gf_fseek(input, 0, SEEK_SET); /* Initializing the progressive reader */ memset(&reader, 0, sizeof(ISOProgressiveReader)); reading_thread = gf_th_new("ISO reading thread"); reader.mutex = gf_mx_new("ISO Segment"); reader.do_run = GF_TRUE; /* we want to parse the first track */ reader.track_id = 1; /* start the async parsing */ gf_th_run(reading_thread, iso_progressive_read_thread, &reader); /* start the data reading */ reader.data_size = BUFFER_BLOCK_SIZE; reader.data = (u8 *)gf_malloc(reader.data_size); reader.valid_data_size = 0; total_read_bytes = 0; while (1) { /* block the parser until we are done manipulating the data buffer */ gf_mx_p(reader.mutex); if (reader.valid_data_size + BUFFER_BLOCK_SIZE > MAX_BUFFER_SIZE) { /* regulate the reader to limit the max buffer size and let some time to the parser to release buffer data */ fprintf(stdout, "Buffer full (%d/%d)- waiting to read next data \r", reader.valid_data_size, reader.data_size); gf_mx_v(reader.mutex); //gf_sleep(10); } else { /* make sure we have enough space in the buffer to read the next bloc of data */ if (reader.valid_data_size + BUFFER_BLOCK_SIZE > reader.data_size) { reader.data = (u8 *)gf_realloc(reader.data, reader.data_size + BUFFER_BLOCK_SIZE); reader.data_size += BUFFER_BLOCK_SIZE; } /* read the next bloc of data and update the data buffer url */ read_bytes = fread(reader.data+reader.valid_data_size, 1, BUFFER_BLOCK_SIZE, input); total_read_bytes += read_bytes; fprintf(stdout, "Read "LLD" bytes of "LLD" bytes from input file %s (buffer status: %5d/%5d)\r", total_read_bytes, file_size, argv[1], reader.valid_data_size, reader.data_size); if (read_bytes) { reader.valid_data_size += read_bytes; sprintf(reader.data_url, "gmem://%d@%p", reader.valid_data_size, reader.data); } else { /* end of file we can quit */ gf_mx_v(reader.mutex); break; } /* if the file is not yet opened (no movie), open it in progressive mode (to update its data later on) */ if (!reader.movie) { /* let's initialize the parser */ e = gf_isom_open_progressive(reader.data_url, 0, 0, &reader.movie, &missing_bytes); if (reader.movie) { gf_isom_set_single_moof_mode(reader.movie, GF_TRUE); } /* we can let parser try to work now */ gf_mx_v(reader.mutex); if ((e == GF_OK || e == GF_ISOM_INCOMPLETE_FILE) && reader.movie) { /* nothing to do, this is normal */ } else { fprintf(stdout, "Error opening fragmented mp4 in progressive mode: %s (missing "LLD" bytes)\n", gf_error_to_string(e), missing_bytes); ret = 1; goto exit; } } else { /* let inform the parser that the buffer has been updated with new data */ e = gf_isom_refresh_fragmented(reader.movie, &missing_bytes, reader.data_url); /* we can let parser try to work now */ gf_mx_v(reader.mutex); if (e != GF_OK && e != GF_ISOM_INCOMPLETE_FILE) { fprintf(stdout, "Error refreshing fragmented mp4: %s (missing "LLD" bytes)\n", gf_error_to_string(e), missing_bytes); ret = 1; goto exit; } } //gf_sleep(1); } } exit: /* stop the parser */ reader.do_run = GF_FALSE; gf_th_stop(reading_thread); /* clean structures */ gf_th_del(reading_thread); gf_mx_del(reader.mutex); gf_free(reader.data); gf_isom_close(reader.movie); gf_fclose(input); gf_sys_close(); return ret; }