void CPlayerMedia::synchronize_rtp_bytestreams (rtcp_sync_t *sync) { if (is_audio()) { player_error_message("Attempt to syncronize audio byte stream"); return; } if (m_rtp_byte_stream != NULL) m_rtp_byte_stream->synchronize(sync); }
int create_media_for_mpeg2t_file (CPlayerSession *psptr, const char *name, int have_audio_driver, control_callback_vft_t *cc_vft) { FILE *ifile; uint8_t buffer[188]; ifile = fopen(name, FOPEN_READ_BINARY); if (ifile == NULL) { psptr->set_message("Couldn't open file %s", name); return -1; } if (fread(buffer, 1, 1, ifile) <= 0) { psptr->set_message("Couldn't read file %s", name); fclose(ifile); return -1; } if (buffer[0] != MPEG2T_SYNC_BYTE) { psptr->set_message("File is not mpeg2 transport %s", name); fclose(ifile); return -1; } CMpeg2tFile *tfile = new CMpeg2tFile(name, ifile); int ret; psptr->session_set_seekable(0); ret = tfile->create(psptr); if (ret < 0) { delete tfile; return ret; } ret = tfile->create_media(psptr, cc_vft); if (ret < 0) { player_error_message("mpeg2t file found"); delete tfile; } psptr->set_session_desc(0, name); return ret; }
int CMpeg2fVideoByteStream::get_timestamp_for_frame (mpeg2t_frame_t *fptr, frame_timestamp_t *ts) { #ifdef DEBUG_MPEG2T_PSTS if (fptr->have_dts) { player_debug_message("video frame len %d have dts %d ts "U64, fptr->frame_len, fptr->have_dts, fptr->dts); } if (fptr->have_ps_ts) { player_debug_message("video frame len %d have psts %d ts "U64, fptr->frame_len, fptr->have_ps_ts, fptr->ps_ts); } #endif #if 0 if (m_es_pid->stream_type == MPEG2T_STREAM_H264) { if (fptr->have_dts || fptr->have_ps_ts) { if (fptr->have_dts) outts = fptr->dts; else outts = fptr->ps_ts; outts *= TO_U64(1000); outts /= TO_U64(90000); // get msec from 90000 timescale return 0; } return -1; } uint64_t ts; // m_es_pid->frame_rate = 24; double value = 90000.0 / m_es_pid->frame_rate; uint64_t frame_time = (uint64_t)value; if (fptr->have_ps_ts == 0 && fptr->have_dts == 0) { // We don't have a timestamp on this - just increment from // the previous timestamp. if (m_timestamp_loaded == 0) return -1; if (m_es_pid->info_loaded == 0) return -1; outts = m_prev_ts + frame_time; m_have_prev_frame_type = 1; m_prev_frame_type = fptr->frame_type; m_prev_ts = outts; outts *= TO_U64(1000); outts /= TO_U64(90000); // get msec from 90000 timescale return 0; } m_timestamp_loaded = 1; if (fptr->have_dts != 0) { outts = fptr->dts; } else { ts = fptr->ps_ts; if (m_have_prev_frame_type) { if (fptr->frame_type == 3) { // B frame outts = ts; } else { outts = m_prev_ts + frame_time; } } else { if (fptr->frame_type == 1) { uint16_t temp_ref = MP4AV_Mpeg3PictHdrTempRef(fptr->frame + fptr->pict_header_offset); ts -= ((temp_ref + 1) * m_es_pid->tick_per_frame); outts = ts; } else { player_error_message( "no psts and no prev frame"); outts = ts; } } } m_have_prev_frame_type = 1; m_prev_frame_type = fptr->frame_type; m_prev_ts = outts; outts *= TO_U64(1000); outts /= TO_U64(90000); // get msec from 90000 timescale return 0; #endif ts->timestamp_is_pts = fptr->have_dts == false; uint64_t outts; if (fptr->have_dts) outts = fptr->dts; else outts = fptr->ps_ts; outts *= TO_U64(1000); outts /= TO_U64(90000); // get msec from 90000 timescale ts->msec_timestamp = outts; return 0; }
bool CRtpByteStream::start_next_frame (uint8_t **buffer, uint32_t *buflen, frame_timestamp_t *pts, void **ud) { uint16_t seq = 0; uint32_t rtp_ts = 0; uint64_t timetick; uint64_t ts = 0; int first = 0; int finished = 0; rtp_packet *rpak; int32_t diff; diff = m_buffer_len - m_bytes_used; if (diff >= 2) { // Still bytes in the buffer... *buffer = m_buffer + m_bytes_used; *buflen = diff; #ifdef DEBUG_RTP_FRAMES rtp_message(LOG_DEBUG, "%s Still left - %d bytes", m_name, *buflen); #endif #if 0 rtp_message(LOG_DEBUG, "%s start %02x %02x %02x %02x %02x", m_name, (*buffer)[0], (*buffer)[1], (*buffer)[2], (*buffer)[3], (*buffer)[4]); #endif pts->msec_timestamp = m_last_realtime; pts->audio_freq_timestamp = m_last_rtp_ts; pts->audio_freq = m_timescale; pts->timestamp_is_pts = true; return true; } else { check_seq(m_head->rtp_pak_seq); m_buffer_len = 0; while (finished == 0) { rpak = m_head; if (rpak == NULL) { // incomplete frame - bail on this player_error_message("%s - This should never happen - rtp bytestream" "is incomplete and active", m_name); player_error_message("Please report to mpeg4ip"); player_error_message("first %d seq %u ts %x blen %d", first, seq, rtp_ts, m_buffer_len); m_buffer_len = 0; m_bytes_used = 0; return 0; } remove_packet_rtp_queue(rpak, 0); if (first == 0) { seq = rpak->rtp_pak_seq + 1; ts = rpak->pd.rtp_pd_timestamp; rtp_ts = rpak->rtp_pak_ts; first = 1; } else { if ((seq != rpak->rtp_pak_seq) || (rtp_ts != rpak->rtp_pak_ts)) { if (seq != rpak->rtp_pak_seq) { rtp_message(LOG_INFO, "%s missing rtp sequence - should be %u is %u", m_name, seq, rpak->rtp_pak_seq); } else { rtp_message(LOG_INFO, "%s timestamp error - seq %u should be %x is %x", m_name, seq, rtp_ts, rpak->rtp_pak_ts); } m_buffer_len = 0; rtp_ts = rpak->rtp_pak_ts; } seq = rpak->rtp_pak_seq + 1; } uint8_t *from; uint32_t len; from = (uint8_t *)rpak->rtp_data + m_skip_on_advance_bytes; len = rpak->rtp_data_len - m_skip_on_advance_bytes; if ((m_buffer_len + len) >= m_buffer_len_max) { // realloc m_buffer_len_max = m_buffer_len + len + 1024; m_buffer = (uint8_t *)realloc(m_buffer, m_buffer_len_max); } memcpy(m_buffer + m_buffer_len, from, len); m_buffer_len += len; if (rpak->rtp_pak_m == 1) { finished = 1; } set_last_seq(rpak->rtp_pak_seq); xfree(rpak); } m_bytes_used = 0; *buffer = m_buffer + m_bytes_used; *buflen = m_buffer_len - m_bytes_used; #if 0 rtp_message(LOG_DEBUG, "%s start %02x %02x %02x %02x %02x", m_name, (*buffer)[0], (*buffer)[1], (*buffer)[2], (*buffer)[3], (*buffer)[4]); #endif #ifdef DEBUG_RTP_FRAMES rtp_message(LOG_DEBUG, "%s buffer len %d", m_name, m_buffer_len); #endif } timetick = rtp_ts_to_msec(rtp_ts, ts, m_wrap_offset); m_last_rtp_ts = rtp_ts; pts->msec_timestamp = timetick; pts->audio_freq_timestamp = m_last_rtp_ts; pts->audio_freq = m_timescale; pts->timestamp_is_pts = true; return (true); }
/* * Create the media for the quicktime file, and set up some session stuff. */ int create_media_for_avi_file (CPlayerSession *psptr, const char *name, char *errmsg, uint32_t errlen, int have_audio_driver, control_callback_vft_t *cc_vft) { CAviFile *Avifile1 = NULL; avi_t *avi; CPlayerMedia *mptr; avi = AVI_open_input_file(name, 1); if (avi == NULL) { snprintf(errmsg, errlen, "%s", AVI_strerror()); player_error_message("%s", AVI_strerror()); return (-1); } int video_count = 1; codec_plugin_t *plugin; video_query_t vq; const char *codec_name = AVI_video_compressor(avi); player_debug_message("Trying avi video codec %s", codec_name); plugin = check_for_video_codec(STREAM_TYPE_AVI_FILE, codec_name, NULL, -1, -1, NULL, 0, &config); if (plugin == NULL) { video_count = 0; } else { vq.track_id = 1; vq.stream_type = STREAM_TYPE_AVI_FILE; vq.compressor = codec_name; vq.type = -1; vq.profile = -1; vq.fptr = NULL; vq.h = AVI_video_height(avi); vq.w = AVI_video_width(avi); vq.frame_rate = AVI_video_frame_rate(avi); vq.config = NULL; vq.config_len = 0; vq.enabled = 0; vq.reference = NULL; } int have_audio = 0; int audio_count = 0; audio_query_t aq; if (AVI_audio_bytes(avi) != 0) { have_audio = 1; plugin = check_for_audio_codec(STREAM_TYPE_AVI_FILE, NULL, NULL, AVI_audio_format(avi), -1, NULL, 0, &config); if (plugin != NULL) { audio_count = 1; aq.track_id = 1; aq.stream_type = STREAM_TYPE_AVI_FILE; aq.compressor = NULL; aq.type = AVI_audio_format(avi); aq.profile = -1; aq.fptr = NULL; aq.sampling_freq = AVI_audio_rate(avi); aq.chans = AVI_audio_channels(avi); aq.config = NULL; aq.config_len = 0; aq.enabled = 0; aq.reference = NULL; } } if (cc_vft != NULL && cc_vft->media_list_query != NULL) { (cc_vft->media_list_query)(psptr, video_count, &vq, audio_count, &aq); } else { if (video_count != 0) vq.enabled = 1; if (audio_count != 0) aq.enabled = 1; } if ((video_count == 0 || vq.enabled == 0) && (audio_count == 0 || aq.enabled == 0)) { snprintf(errmsg, errlen, "No audio or video tracks enabled or playable"); AVI_close(avi); return -1; } Avifile1 = new CAviFile(name, avi, vq.enabled, audio_count); psptr->set_media_close_callback(close_avi_file, Avifile1); if (video_count != 0 && vq.enabled) { mptr = new CPlayerMedia(psptr); if (mptr == NULL) { return (-1); } video_info_t *vinfo = MALLOC_STRUCTURE(video_info_t); if (vinfo == NULL) return (-1); vinfo->height = vq.h; vinfo->width = vq.w; player_debug_message("avi file h %d w %d frame rate %g", vinfo->height, vinfo->width, vq.frame_rate); plugin = check_for_video_codec(STREAM_TYPE_AVI_FILE, codec_name, NULL, -1, -1, NULL, 0, &config); int ret; ret = mptr->create_video_plugin(plugin, STREAM_TYPE_AVI_FILE, codec_name, -1, -1, NULL, vinfo, NULL, 0); if (ret < 0) { snprintf(errmsg, errlen, "Failed to create video plugin %s", codec_name); player_error_message("Failed to create plugin data"); delete mptr; return -1; } CAviVideoByteStream *vbyte = new CAviVideoByteStream(Avifile1); if (vbyte == NULL) { delete mptr; return (-1); } vbyte->config(AVI_video_frames(avi), vq.frame_rate); ret = mptr->create(vbyte, TRUE, errmsg, errlen); if (ret != 0) { return (-1); } } int seekable = 1; if (have_audio_driver > 0 && audio_count > 0 && aq.enabled != 0) { plugin = check_for_audio_codec(STREAM_TYPE_AVI_FILE, NULL, NULL, aq.type, -1, NULL, 0, &config); CAviAudioByteStream *abyte; mptr = new CPlayerMedia(psptr); if (mptr == NULL) { return (-1); } audio_info_t *ainfo; ainfo = MALLOC_STRUCTURE(audio_info_t); ainfo->freq = aq.sampling_freq; ainfo->chans = aq.chans; ainfo->bitspersample = AVI_audio_bits(avi); int ret; ret = mptr->create_audio_plugin(plugin, aq.stream_type, aq.compressor, aq.type, aq.profile, NULL, ainfo, NULL, 0); if (ret < 0) { delete mptr; player_error_message("Couldn't create audio from plugin %s", plugin->c_name); return -1; } abyte = new CAviAudioByteStream(Avifile1); ret = mptr->create(abyte, FALSE, errmsg, errlen); if (ret != 0) { return (-1); } seekable = 0; } psptr->session_set_seekable(seekable); if (audio_count == 0 && have_audio != 0) { snprintf(errmsg, errlen, "Unknown Audio Codec in avi file "); return (1); } if (video_count != 1) { snprintf(errmsg, errlen, "Unknown Video Codec %s in avi file", codec_name); return (1); } return (0); }
/* * 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) { SDL_sem *master_sem; CClientProcess proc; CMsgQueue master_queue; argv++; argc--; int deb = 0; if (*argv[0] == '-') { argv++; argc--; deb = 1; } open_output("wmp4player.log"); if (proc.enable_communication(deb) < 0) { printf("Could not enable communications\n"); Sleep(10 * 1000); close_output(); return -1; } initialize_plugins(&config); config.InitializeIndexes(); config.ReadVariablesFromRegistry("Software\\Mpeg4ip", "Config"); psptr = NULL; master_sem = NULL; if (*argv == NULL) { proc.initial_response(-1, psptr,"No argument to process"); } else { rtsp_set_error_func(library_message); rtp_set_error_msg_func(library_message); sdp_set_error_func(library_message); http_set_error_func(library_message); master_sem = SDL_CreateSemaphore(0); psptr = start_session(&master_queue, master_sem, NULL, *argv, NULL, config.get_config_value(CONFIG_VOLUME), 100, 100, screen_size); if (psptr == NULL) { proc.initial_response(-1, NULL, NULL); } else { proc.initial_response(0, psptr, psptr->get_message()); } } // Either way - we need to loop and wait until we get the // terminate message int running = 0; int state = 0; while (running == 0) { CMsg *msg; running = proc.receive_messages(psptr); while ((msg = master_queue.get_message()) != NULL) { switch (msg->get_value()) { case MSG_SESSION_FINISHED: proc.send_message(GUI_MSG_SESSION_FINISHED); break; case MSG_SESSION_WARNING: proc.send_string(GUI_MSG_SESSION_WARNING, psptr->get_message()); break; case MSG_SESSION_ERROR: player_error_message("error is \"%s\"", psptr->get_message()); proc.send_string(GUI_MSG_SESSION_ERROR, psptr->get_message()); break; case MSG_RECEIVED_QUIT: proc.send_message(GUI_MSG_RECEIVED_QUIT); break; case MSG_SDL_KEY_EVENT: uint32_t len; void *sdl_event = (void *)msg->get_message(len); proc.send_message(GUI_MSG_SDL_KEY, sdl_event, len); break; } delete msg; } if (psptr != NULL) state = psptr->sync_thread(state); } if (psptr != NULL) { delete psptr; } if (master_sem != NULL) { SDL_DestroySemaphore(master_sem); } // remove invalid global ports config.WriteVariablesToRegistry("Software\\Mpeg4ip", "Config"); close_plugins(); close_output(); return 0; }
/* * C2ConsecIpPort::C2ConsecIpPort() - get 2 consecutive, even-odd, ip * port numbers */ C2ConsecIpPort::C2ConsecIpPort (CIpPort **global, in_port_t start_port) { CIpPort *newone; m_first = m_second = NULL; in_port_t firstport, maxport; maxport = (in_port_t)~0; if (start_port == 0) { firstport = 1024; if (config.get_config_value(CONFIG_IPPORT_MIN) != UINT32_MAX) { firstport = config.get_config_value(CONFIG_IPPORT_MIN); if (config.get_config_value(CONFIG_IPPORT_MAX) != UINT32_MAX) { maxport = config.get_config_value(CONFIG_IPPORT_MAX); if (maxport <= firstport) { player_error_message("IP port configuration error - %u %u - using 65535 as max port value", firstport, maxport); maxport = (in_port_t)~0; } } } } else { firstport = start_port; } while (1) { // first, get an even port number. If not even, save it in the // global queue. do { newone = new CIpPort(firstport, maxport); if (newone->valid() == 0) return; if ((newone->get_port_num() & 0x1) == 0x1) { newone->set_next(*global); *global = newone; firstport++; } } while ((newone->get_port_num() & 0x1) == 0x1); player_debug_message("First port is %d", newone->get_port_num()); // Okay, save the first, get the 2nd. If okay, just return m_first = newone; in_port_t next; next = m_first->get_port_num() + 1; m_second = new CIpPort(next, next); if ((m_second->valid() == 1) && (m_second->get_port_num() == next)) { player_debug_message("Ip ports are %u %u", next - 1, next); return; } else { player_debug_message("Got port %d invalid %d", m_second->get_port_num(), m_second->valid()); } // Not okay - save both off in the global queue, and try again... m_first->set_next(*global); *global = m_first; m_first = NULL; firstport = m_second->get_port_num() + 1; m_second->set_next(*global); *global = m_second; m_second = NULL; } }
/* * play_all_media - get all media to play */ int CPlayerSession::play_all_media (int start_from_begin, double start_time, char *errmsg, uint32_t errlen) { int ret; CPlayerMedia *p; if (m_set_end_time == 0) { range_desc_t *range; if (m_sdp_info && m_sdp_info->session_range.have_range != FALSE) { range = &m_sdp_info->session_range; } else { range = NULL; p = m_my_media; while (range == NULL && p != NULL) { media_desc_t *media; media = p->get_sdp_media_desc(); if (media && media->media_range.have_range) { range = &media->media_range; } p = p->get_next(); } } if (range != NULL) { m_end_time = (uint64_t)(range->range_end * 1000.0); m_set_end_time = 1; } } p = m_my_media; m_session_state = SESSION_BUFFERING; if (m_paused == 1 && start_time == 0.0 && start_from_begin == FALSE) { /* * we were paused. Continue. */ m_play_start_time = m_current_time; start_time = UINT64_TO_DOUBLE(m_current_time); start_time /= 1000.0; player_debug_message("Restarting at " U64 ", %g", m_current_time, start_time); } else { /* * We might have been paused, but we're told to seek */ // Indicate what time we're starting at for sync task. m_play_start_time = (uint64_t)(start_time * 1000.0); } m_paused = 0; send_sync_thread_a_message(MSG_START_SESSION); // If we're doing aggregate rtsp, send the play command... if (session_control_is_aggregate() && m_dont_send_first_rtsp_play == 0) { char buffer[80]; rtsp_command_t cmd; rtsp_decode_t *decode; memset(&cmd, 0, sizeof(rtsp_command_t)); if (m_set_end_time != 0) { uint64_t stime = (uint64_t)(start_time * 1000.0); sprintf(buffer, "npt="U64"."U64"-"U64"."U64, stime / 1000, stime % 1000, m_end_time / 1000, m_end_time % 1000); cmd.range = buffer; } if (rtsp_send_aggregate_play(m_rtsp_client, m_session_control_url, &cmd, &decode) != 0) { if (errmsg != NULL) { snprintf(errmsg, errlen, "RTSP Aggregate Play Error %s-%s", decode->retcode, decode->retresp != NULL ? decode->retresp : ""); } player_debug_message("RTSP aggregate play command failed"); free_decode_response(decode); return (-1); } if (decode->rtp_info == NULL) { player_error_message("No rtp info field"); } else { player_debug_message("rtp info is \'%s\'", decode->rtp_info); } int ret = process_rtsp_rtpinfo(decode->rtp_info, this, NULL); free_decode_response(decode); if (ret < 0) { if (errmsg != NULL) { snprintf(errmsg, errlen, "RTSP aggregate RtpInfo response failure"); } player_debug_message("rtsp aggregate rtpinfo failed"); return (-1); } } m_dont_send_first_rtsp_play = 0; while (p != NULL) { ret = p->do_play(start_time, errmsg, errlen); if (ret != 0) return (ret); p = p->get_next(); } return (0); }
/* * create_streaming - create a session for streaming. Create an * RTSP session with the server, get the SDP information from it. */ int CPlayerSession::create_streaming_ondemand (const char *url, char *errmsg, uint32_t errlen, int use_tcp) { rtsp_command_t cmd; rtsp_decode_t *decode; sdp_decode_info_t *sdpdecode; int dummy; int err; // streaming has seek capability (at least on demand) session_set_seekable(1); player_debug_message("Creating streaming %s", url); memset(&cmd, 0, sizeof(rtsp_command_t)); /* * create RTSP session */ if (use_tcp != 0) { m_rtsp_client = rtsp_create_client_for_rtp_tcp(url, &err); } else { m_rtsp_client = rtsp_create_client(url, &err); } if (m_rtsp_client == NULL) { snprintf(errmsg, errlen, "Failed to create RTSP client"); player_error_message("Failed to create rtsp client - error %d", err); return (err); } m_rtp_over_rtsp = use_tcp; cmd.accept = "application/sdp"; /* * Send the RTSP describe. This should return SDP information about * the session. */ int rtsp_resp; rtsp_resp = rtsp_send_describe(m_rtsp_client, &cmd, &decode); if (rtsp_resp != RTSP_RESPONSE_GOOD) { int retval; if (decode != NULL) { retval = (((decode->retcode[0] - '0') * 100) + ((decode->retcode[1] - '0') * 10) + (decode->retcode[2] - '0')); snprintf(errmsg, errlen, "RTSP describe error %d %s", retval, decode->retresp != NULL ? decode->retresp : ""); free_decode_response(decode); } else { retval = -1; snprintf(errmsg, errlen, "RTSP return invalid %d", rtsp_resp); } player_error_message("Describe response not good\n"); return (retval); } sdpdecode = set_sdp_decode_from_memory(decode->body); if (sdpdecode == NULL) { snprintf(errmsg, errlen, "Memory failure"); player_error_message("Couldn't get sdp decode\n"); free_decode_response(decode); return (-1); } /* * Decode the SDP information into structures we can use. */ err = sdp_decode(sdpdecode, &m_sdp_info, &dummy); free(sdpdecode); if (err != 0) { snprintf(errmsg, errlen, "Couldn't decode session description %s", decode->body); player_error_message("Couldn't decode sdp %s", decode->body); free_decode_response(decode); return (-1); } if (dummy != 1) { snprintf(errmsg, errlen, "Incorrect number of sessions in sdp decode %d", dummy); player_error_message("%s", errmsg); free_decode_response(decode); return (-1); } /* * Make sure we can use the urls in the sdp info */ if (decode->content_location != NULL) { // Note - we may have problems if the content location is not absolute. m_content_base = strdup(decode->content_location); } else if (decode->content_base != NULL) { m_content_base = strdup(decode->content_base); } else { int urllen = strlen(url); if (url[urllen] != '/') { char *temp; temp = (char *)malloc(urllen + 2); strcpy(temp, url); strcat(temp, "/"); m_content_base = temp; } else { m_content_base = strdup(url); } } convert_relative_urls_to_absolute(m_sdp_info, m_content_base); if (m_sdp_info->control_string != NULL) { player_debug_message("setting control url to %s", m_sdp_info->control_string); set_session_control_url(m_sdp_info->control_string); } free_decode_response(decode); m_streaming = 1; m_streaming_ondemand = (get_range_from_sdp(m_sdp_info) != NULL); return (0); }
static int create_media_from_sdp (CPlayerSession *psptr, session_desc_t *sdp, char *errmsg, uint32_t errlen, int have_audio_driver, int broadcast, int only_check_first, control_callback_vft_t *cc_vft) { int err; int media_count = 0; int invalid_count = 0; int have_audio_but_no_driver = 0; char buffer[80]; codec_plugin_t *codec; format_list_t *fmt; int audio_count, video_count; int audio_offset, video_offset; int ix; if (sdp->session_name != NULL) { snprintf(buffer, sizeof(buffer), "Name: %s", sdp->session_name); psptr->set_session_desc(0, buffer); } if (sdp->session_desc != NULL) { snprintf(buffer, sizeof(buffer), "Description: %s", sdp->session_desc); psptr->set_session_desc(1, buffer); } #ifndef _WIN32 if (sdp->media != NULL && sdp->media->next == NULL && strcasecmp(sdp->media->media, "video") == 0 && sdp->media->fmt != NULL && strcmp(sdp->media->fmt->fmt, "33") == 0) { // we have a mpeg2 transport stream return (create_mpeg2t_session(psptr, NULL, sdp, errmsg, errlen, have_audio_driver, cc_vft)); } #endif media_desc_t *sdp_media; audio_count = video_count = 0; for (sdp_media = psptr->get_sdp_info()->media; sdp_media != NULL; sdp_media = sdp_media->next) { if (strcasecmp(sdp_media->media, "audio") == 0) { if (have_audio_driver == 0) { have_audio_but_no_driver = 1; } else { audio_count++; } } else if (strcasecmp(sdp_media->media, "video") == 0) { video_count++; } } video_query_t *vq; audio_query_t *aq; if (video_count > 0) { vq = (video_query_t *)malloc(sizeof(video_query_t) * video_count); } else { vq = NULL; } if (audio_count > 0) { aq = (audio_query_t *)malloc(sizeof(audio_query_t) * audio_count); } else { aq = NULL; } video_offset = audio_offset = 0; for (sdp_media = psptr->get_sdp_info()->media; sdp_media != NULL; sdp_media = sdp_media->next) { if (have_audio_driver != 0 && strcasecmp(sdp_media->media, "audio") == 0) { fmt = sdp_media->fmt; codec = NULL; while (codec == NULL && fmt != NULL) { codec = check_for_audio_codec(STREAM_TYPE_RTP, NULL, fmt, -1, -1, NULL, 0, &config); if (codec == NULL) { if (only_check_first != 0) fmt = NULL; else fmt = fmt->next; } } if (codec == NULL) { invalid_count++; continue; } else { // set up audio qualifier aq[audio_offset].track_id = audio_offset; aq[audio_offset].stream_type = STREAM_TYPE_RTP; aq[audio_offset].compressor = NULL; aq[audio_offset].type = -1; aq[audio_offset].profile = -1; aq[audio_offset].fptr = fmt; aq[audio_offset].sampling_freq = -1; aq[audio_offset].chans = -1; aq[audio_offset].enabled = 0; aq[audio_offset].reference = NULL; audio_offset++; } } else if (strcasecmp(sdp_media->media, "video") == 0) { fmt = sdp_media->fmt; codec = NULL; while (codec == NULL && fmt != NULL) { codec = check_for_video_codec(STREAM_TYPE_RTP, NULL, fmt, -1, -1, NULL, 0, &config); if (codec == NULL) { if (only_check_first != 0) fmt = NULL; else fmt = fmt->next; } } if (codec == NULL) { invalid_count++; continue; } else { vq[video_offset].track_id = video_offset; vq[video_offset].stream_type = STREAM_TYPE_RTP; vq[video_offset].compressor = NULL; vq[video_offset].type = -1; vq[video_offset].profile = -1; vq[video_offset].fptr = fmt; vq[video_offset].h = -1; vq[video_offset].w = -1; vq[video_offset].frame_rate = -1; vq[video_offset].enabled = 0; vq[video_offset].reference = NULL; video_offset++; } } else { player_error_message("Skipping media type `%s\'", sdp_media->media); continue; } } // okay - from here, write the callback call, and go ahead... if (cc_vft != NULL && cc_vft->media_list_query != NULL) { (cc_vft->media_list_query)(psptr, video_offset, vq, audio_offset, aq); } else { if (video_offset > 0) { vq[0].enabled = 1; } if (audio_offset > 0) { aq[0].enabled = 1; } } for (ix = 0; ix < video_offset; ix++) { if (vq[ix].enabled != 0) { CPlayerMedia *mptr = new CPlayerMedia(psptr); err = mptr->create_streaming(vq[ix].fptr->media, errmsg, errlen, broadcast, config.get_config_value(CONFIG_USE_RTP_OVER_RTSP), media_count); if (err < 0) { return (-1); } if (err > 0) { delete mptr; } else media_count++; } } for (ix = 0; ix < audio_offset; ix++) { if (aq[ix].enabled != 0) { CPlayerMedia *mptr = new CPlayerMedia(psptr); err = mptr->create_streaming(aq[ix].fptr->media, errmsg, errlen, broadcast, config.get_config_value(CONFIG_USE_RTP_OVER_RTSP), media_count); if (err < 0) { return (-1); } if (err > 0) { delete mptr; } else media_count++; } } if (aq != NULL) free(aq); if (vq != NULL) free(vq); if (media_count == 0) { snprintf(errmsg, errlen, "No known codecs found in SDP"); return (-1); } psptr->streaming_media_set_up(); if (have_audio_but_no_driver > 0) { snprintf(errmsg, errlen, "Not playing audio codecs - no driver"); return (1); } if (invalid_count > 0) { snprintf(errmsg, errlen, "There were unknowns codecs during decode - playing valid ones"); return (1); } return (0); }