/* * Create - will determine pids and psts ranges in file. Will also * loop through the file and determine CFilePosRec points at percentages */ int CMpeg2tFile::create (CPlayerSession *psptr) { m_mpeg2t = create_mpeg2_transport(); if (m_mpeg2t == NULL) { psptr->set_message("Couldn't create mpeg2 transport"); fclose(m_ifile); return -1; } // nice, large buffers to process m_buffer_size_max = 188 * 2000; m_buffer = (uint8_t *)malloc(m_buffer_size_max); if (m_buffer == NULL) { psptr->set_message("Malloc error"); return -1; } m_buffer[0] = MPEG2T_SYNC_BYTE; m_buffer_size = fread(&m_buffer[1], 1, m_buffer_size_max - 1, m_ifile) + 1; bool done = false; mpeg2t_pid_t *pidptr; uint32_t buflen_used; bool have_psts = false; uint64_t earliest_psts = 0; mpeg2t_es_t *es_pid; int olddebuglevel; olddebuglevel = config.get_config_value(CONFIG_MPEG2T_DEBUG); if (olddebuglevel != LOG_DEBUG) mpeg2t_set_loglevel(LOG_CRIT); m_mpeg2t->save_frames_at_start = 1; /* * We need to determine which PIDs are present, and try to establish * a starting psts. We also want to establish what type of video and * audio are in the mix. Note: if we try to run this on a file that * we don't understand the video, this could take a while, because the * info never gets loaded. */ do { m_buffer_on = 0; while (m_buffer_on + 188 < m_buffer_size && done == false) { pidptr = mpeg2t_process_buffer(m_mpeg2t, &m_buffer[m_buffer_on], m_buffer_size - m_buffer_on, &buflen_used); m_buffer_on += buflen_used; if (pidptr != NULL && pidptr->pak_type == MPEG2T_ES_PAK) { es_pid = (mpeg2t_es_t *)pidptr; mpeg2t_frame_t *fptr; // determine earliest PS_TS while ((fptr = mpeg2t_get_es_list_head(es_pid)) != NULL) { if (fptr->have_ps_ts != 0 || fptr->have_dts != 0) { uint64_t ps_ts = 0; bool store_psts = true; if (fptr->have_dts != 0) { ps_ts = fptr->dts; } else { if (es_pid->is_video == 1) { // mpeg2 // video - make sure we get the first I frame, then we can // get the real timestamp if (fptr->frame_type != 1) { store_psts = false; } else { ps_ts = fptr->ps_ts; uint16_t temp_ref = MP4AV_Mpeg3PictHdrTempRef(fptr->frame + fptr->pict_header_offset); ps_ts -= ((temp_ref + 1) * es_pid->tick_per_frame); } } else { ps_ts = fptr->ps_ts; } } if (store_psts) { // when we have the first psts for a ES_PID, turn off // parsing frames for that PID. mpeg2t_set_frame_status(es_pid, MPEG2T_PID_NOTHING); if (have_psts) { earliest_psts = MIN(earliest_psts, ps_ts); } else { earliest_psts = ps_ts; have_psts = true; } } } mpeg2t_free_frame(fptr); } // Each time, search through and see if there are any ES_PIDs // that have not returned a psts. We're done when the info is // loaded for all the es pids. pidptr = m_mpeg2t->pas.pid.next_pid; bool finished = true; while (pidptr != NULL && finished) { if (pidptr->pak_type == MPEG2T_ES_PAK) { es_pid = (mpeg2t_es_t *)pidptr; if (es_pid->info_loaded == 0) { finished = false; } } pidptr = pidptr->next_pid; } done = finished || have_psts; } } if (done == false) { m_buffer_size = fread(m_buffer, 1, m_buffer_size_max, m_ifile); } } while (m_buffer_size >=188 && done == false); if (done == false) { psptr->set_message("Could not find information in TS"); mpeg2t_set_loglevel(olddebuglevel); return -1; } #ifdef DEBUG_MPEG2F_SEARCH mpeg2f_message(LOG_DEBUG, "initial psts is "U64, earliest_psts); #endif m_start_psts = earliest_psts; // Now, we'll try to build a rough index for the file // enable psts reading for the pid for (pidptr = m_mpeg2t->pas.pid.next_pid; pidptr != NULL; pidptr = pidptr->next_pid) { if (pidptr->pak_type == MPEG2T_ES_PAK) { es_pid = (mpeg2t_es_t *)pidptr; mpeg2t_set_frame_status(es_pid, MPEG2T_PID_REPORT_PSTS); } } m_file_record.record_point(0, earliest_psts, 0); fpos_t fpos; uint64_t end; uint64_t perc, cur; // find out the length of the file. struct stat filestat; if (fstat(fileno(m_ifile), &filestat) != 0) { return -1; } end = filestat.st_size; perc = end; // perc is what size of the file to skip through to get a rough // timetable. We want to do 10% chunks, or 100Mb chunks, whichever is // less. while (perc > TO_U64(100000000)) { perc /= 2; } if (perc > (end / TO_U64(10))) { perc = end / TO_U64(10); } if (perc < (end / TO_U64(50))) { perc = end / TO_U64(50); } #ifdef DEBUG_MPEG2F_SEARCH mpeg2f_message(LOG_DEBUG, "perc is "U64" "U64, perc, (perc * TO_U64(100)) / end ); #endif cur = perc; bool is_seekable = true; uint64_t last_psts, ts; last_psts = earliest_psts; // Now - skip to the next perc chunk, and try to find the next psts // we'll record this info. do { #ifdef DEBUG_MPEG2F_SEARCH mpeg2f_message(LOG_DEBUG, "current "U64" end "U64, cur, end); #endif VAR_TO_FPOS(fpos, cur); fsetpos(m_ifile, &fpos); done = false; uint64_t count = 0; m_buffer_on = 0; m_buffer_size = 0; do { if (m_buffer_on + 188 > m_buffer_size) { if (m_buffer_on < m_buffer_size) { memmove(m_buffer, m_buffer + m_buffer_on, m_buffer_size - m_buffer_on); m_buffer_on = m_buffer_size - m_buffer_on; } else { m_buffer_on = 0; } m_buffer_size = fread(m_buffer + m_buffer_on, 1, (188 * 10) - m_buffer_on, m_ifile); count += m_buffer_size - m_buffer_on; m_buffer_size += m_buffer_on; m_buffer_on = 0; if (m_buffer_size < 188) { m_buffer_size = 0; done = true; } } pidptr = mpeg2t_process_buffer(m_mpeg2t, m_buffer + m_buffer_on, m_buffer_size - m_buffer_on, &buflen_used); m_buffer_on += buflen_used; if (pidptr != NULL && pidptr->pak_type == MPEG2T_ES_PAK) { es_pid = (mpeg2t_es_t *)pidptr; // If we have a psts, record it. // If it is less than the previous one, we've got a discontinuity, so // we can't seek. if (es_pid->have_ps_ts || es_pid->have_dts) { ts = es_pid->have_ps_ts ? es_pid->ps_ts : es_pid->dts; if (ts < last_psts) { player_error_message("pid %x psts "U64" is less than prev record point "U64, es_pid->pid.pid, ts, last_psts); cur = end; is_seekable = false; } else { #ifdef DEBUG_MPEG2F_SEARCH mpeg2f_message(LOG_DEBUG, "pid %x psts "U64" %d", pidptr->pid, ts, es_pid->is_video); #endif m_file_record.record_point(cur, ts, 0); } done = true; } } } while (done == false && count < perc / 2); cur += perc; } while (cur < end - (m_buffer_size_max * 2)); //mpeg2f_message(LOG_DEBUG, "starting end search"); // Now, we'll go to close to the end of the file, and look for a // final PSTS. This gives us a rough estimate of the elapsed time long seek_offset; seek_offset = 0; seek_offset -= (m_buffer_size_max) * 2; fseek(m_ifile, seek_offset, SEEK_END); m_buffer_on = m_buffer_size = 0; uint64_t max_psts; max_psts = m_start_psts; do { while (m_buffer_on + 188 <= m_buffer_size) { pidptr = mpeg2t_process_buffer(m_mpeg2t, &m_buffer[m_buffer_on], m_buffer_size - m_buffer_on, &buflen_used); m_buffer_on += buflen_used; if (pidptr != NULL && pidptr->pak_type == MPEG2T_ES_PAK) { es_pid = (mpeg2t_es_t *)pidptr; if (es_pid->have_ps_ts) { es_pid->have_ps_ts = 0; max_psts = MAX(es_pid->ps_ts, max_psts); } else if (es_pid->have_dts) { es_pid->have_dts = 0; max_psts = MAX(es_pid->dts, max_psts); } } } if (m_buffer_size > m_buffer_on) { memmove(m_buffer, m_buffer + m_buffer_on, m_buffer_size - m_buffer_on); } m_buffer_on = m_buffer_size - m_buffer_on; m_buffer_size = fread(m_buffer + m_buffer_on, 1, m_buffer_size_max - m_buffer_on, m_ifile); m_buffer_size += m_buffer_on; m_buffer_on = 0; if (m_buffer_size < 188) m_buffer_size = 0; } while (m_buffer_size > 188) ; m_last_psts = max_psts; // Calculate the rough max time; hopefully it will be greater than the // initial... m_max_time = max_psts; m_max_time -= m_start_psts; m_max_time /= 90000.0; #ifdef DEBUG_MPEG2F_SEARCH player_debug_message("last psts is "U64" "U64" %g", max_psts, (max_psts - m_start_psts) / TO_U64(90000), m_max_time); #endif mpeg2t_set_loglevel(olddebuglevel); if (is_seekable) { psptr->session_set_seekable(1); } m_ts_seeked_in_msec = UINT64_MAX; rewind(m_ifile); return 0; }
int main (int argc, char **argv) { FILE *ifile; uint8_t *buffer, *ptr; uint32_t buflen, readfromfile; uint32_t offset; int done_with_buf; mpeg2t_t *mpeg2t; mpeg2t_es_t *es_pid; mpeg2t_pid_t *pidptr; bool verbose = false; fpos_t pos; const char *ProgName = argv[0]; const char *usage = ""; uint16_t pid = 0; const char *filename; // int lastcc, ccset; while (true) { int c = -1; int option_index = 0; static struct option long_options[] = { { "help", 0, 0, '?' }, { "version", 0, 0, 'v'}, { "verbose", 0, 0, 'V'}, { "pid", 1, 0, 'p' }, { NULL, 0, 0, 0 } }; c = getopt_long_only(argc, argv, "?vVp:", long_options, &option_index); if (c == -1) break; switch (c) { case '?': printf("%s", usage); exit(1); case 'V': verbose = true; break; case 'v': printf("%s - %s version %s", ProgName, MPEG4IP_PACKAGE, MPEG4IP_VERSION); exit(1); case 'p': { int readval; if (sscanf(optarg, "%i", &readval) != 1) { fprintf(stderr, "can't read pid value %s\n", optarg); exit(1); } if (readval > 0x1fff) { fprintf(stderr, "illegal pid value %s\n", optarg); } pid = readval; } } } if (pid == 0) { fprintf(stderr, "must specify pid to extract\n"); exit(-1); } filename = argv[optind]; buffer = (uint8_t *)malloc(BUFFER_SIZE); if (verbose) mpeg2t_set_loglevel(LOG_DEBUG); else mpeg2t_set_loglevel(LOG_ERR); mpeg2t = create_mpeg2_transport(); mpeg2t->save_frames_at_start = 1; ifile = fopen(filename, FOPEN_READ_BINARY); if (ifile == NULL) { fprintf(stderr, "Couldn't open file %s\n", filename); exit(1); } buflen = 0; readfromfile = 0; char outfilename[MAXPATHLEN], spid[20]; strip_filename(filename, outfilename); sprintf(spid, ".%u", pid); strcat(outfilename, spid); FILE *ofile; // bool has_pat = false; ofile = fopen(outfilename, FOPEN_WRITE_BINARY); //lastcc = 0; while (!feof(ifile)) { if (buflen > 0) { memmove(buffer, buffer + readfromfile - buflen, buflen); } fgetpos(ifile, &pos); uint64_t position; FPOS_TO_VAR(pos, uint64_t, position); fprintf(stdout, "file pos %llu\n", position); readfromfile = buflen + fread(buffer + buflen, 1, BUFFER_SIZE - buflen, ifile); buflen = readfromfile; ptr = buffer; done_with_buf = 0; while (done_with_buf == 0) { pidptr = mpeg2t_process_buffer(mpeg2t, ptr, buflen, &offset); ptr += offset; buflen -= offset; if (buflen < 188) { done_with_buf = 1; } if (pidptr != NULL && pidptr->pak_type == MPEG2T_ES_PAK) { mpeg2t_frame_t *p; es_pid = (mpeg2t_es_t *)pidptr; while ((p = mpeg2t_get_es_list_head(es_pid)) != NULL) { if (pidptr->pid == pid) { printf("Pid %x %d frame len %5d psts %d "U64" dts %d "U64"\n", pidptr->pid, es_pid->stream_type, p->frame_len, p->have_ps_ts, p->ps_ts, p->have_dts, p->dts); fwrite(p->frame, 1, p->frame_len, ofile); } mpeg2t_free_frame(p); } } } } free(buffer); fclose(ifile); fclose(ofile); return 0; }
int main (int argc, char **argv) { FILE *ifile; uint8_t *buffer, *ptr; uint32_t buflen, readfromfile; uint32_t offset; int done_with_buf; mpeg2t_t *mpeg2t; mpeg2t_es_t *es_pid; mpeg2t_pid_t *pidptr; bool verbose = false; fpos_t pos; const char *ProgName = argv[0]; const char *usage = ""; uint16_t pid = 0; bool diff = false; // int lastcc, ccset; while (true) { int c = -1; int option_index = 0; static struct option long_options[] = { { "help", 0, 0, '?' }, { "version", 0, 0, 'v'}, { "verbose", 0, 0, 'V'}, { "pid", 1, 0, 'p' }, { "diff", 0, 0, 'd' }, { NULL, 0, 0, 0 } }; c = getopt_long_only(argc, argv, "?vVp:d", long_options, &option_index); if (c == -1) break; switch (c) { case '?': printf("%s", usage); exit(1); case 'V': verbose = true; break; case 'v': printf("%s - %s version %s", ProgName, MPEG4IP_PACKAGE, MPEG4IP_VERSION); exit(1); case 'd': diff = true; break; case 'p': { int readval; if (sscanf(optarg, "%i", &readval) != 1) { fprintf(stderr, "can't read pid value %s\n", optarg); exit(1); } if (readval > 0x1fff) { fprintf(stderr, "illegal pid value %s\n", optarg); } pid = readval; } } } argc -= optind; argv += optind; buffer = (uint8_t *)malloc(BUFFER_SIZE); if (verbose) mpeg2t_set_loglevel(LOG_DEBUG); else mpeg2t_set_loglevel(LOG_ERR); mpeg2t = create_mpeg2_transport(); mpeg2t->save_frames_at_start = 1; ifile = fopen(*argv, FOPEN_READ_BINARY); if (ifile == NULL) { fprintf(stderr, "Couldn't open file %s\n", *argv); exit(1); } buflen = 0; readfromfile = 0; uint64_t last_pts = 0; //lastcc = 0; while (!feof(ifile)) { if (buflen > 0) { memmove(buffer, buffer + readfromfile - buflen, buflen); } fgetpos(ifile, &pos); if (verbose) { uint64_t position; FPOS_TO_VAR(pos, uint64_t, position); fprintf(stdout, "file pos %llu\n", position); } readfromfile = buflen + fread(buffer + buflen, 1, BUFFER_SIZE - buflen, ifile); buflen = readfromfile; ptr = buffer; done_with_buf = 0; while (done_with_buf == 0) { pidptr = mpeg2t_process_buffer(mpeg2t, ptr, buflen, &offset); ptr += offset; buflen -= offset; if (buflen < 188) { done_with_buf = 1; } if (pidptr != NULL && pidptr->pak_type == MPEG2T_ES_PAK) { mpeg2t_frame_t *p; es_pid = (mpeg2t_es_t *)pidptr; while ((p = mpeg2t_get_es_list_head(es_pid)) != NULL) { if (pid == 0 || pidptr->pid == pid) { printf("Pid %u %d frame len %5u", pidptr->pid, es_pid->stream_type, p->frame_len); uint64_t comp; if (p->have_dts && p->have_ps_ts) { printf(" dts "U64" pts "U64, p->dts, p->ps_ts); comp = p->dts; } else { comp = p->ps_ts; if (p->have_ps_ts) { printf(" pts "U64, p->ps_ts); } if (p->have_dts) { printf(" dts "U64, p->dts); } } if (diff) { if (last_pts != 0) { printf("\tdiff "U64, comp - last_pts); } else { printf("\tno diff"); } last_pts = comp; } printf("\n"); } mpeg2t_free_frame(p); } } } } free(buffer); fclose(ifile); return 0; }