void sound_stop(const function_call& fn) { sound_handler* s = get_sound_handler(); if (s != NULL) { as_sound* snd = cast_to<as_sound>(fn.this_ptr); assert(snd); s->stop_sound(snd->m_id); } }
// The number of milliseconds a sound has been playing. // If the sound is looped, the position is reset to 0 at the beginning of each loop. void get_position(const function_call& fn) { sound_handler* s = get_sound_handler(); if (s != NULL) { as_sound* snd = cast_to<as_sound>(fn.this_ptr); assert(snd); int ms = s->get_position(snd->m_id); fn.result->set_int(ms); } }
void sprite_instance::set_play_state(play_state s) // Stop or play the sprite. { // pauses stream sound sound_handler* sound = get_sound_handler(); if (sound) { if (m_def->m_ss_id >= 0) { sound->pause(m_def->m_ss_id, m_play_state == PLAY ? true : false); } } m_play_state = s; }
// it is running in sound mixer thread bool as_netstream::decode_audio(const AVPacket& pkt, Sint16** data, int* size) { bool ok = false; int frame_size; Uint8* decoder_buf = (Uint8*) malloc((AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2); if (avcodec_decode_audio(m_ACodecCtx, (Sint16*) decoder_buf, &frame_size, pkt.data, pkt.size) >= 0) { sound_handler* sh = get_sound_handler(); if (sh) { sh->cvt(data, size, decoder_buf, frame_size, m_ACodecCtx->channels, m_ACodecCtx->sample_rate); ok = true; } } free(decoder_buf); return ok; }
void sound_start(const function_call& fn) { sound_handler* s = get_sound_handler(); if (s != NULL) { as_sound* snd = cast_to<as_sound>(fn.this_ptr); if (snd) { int offset = 0; int loops = 0; if (fn.nargs >= 2) { offset = fn.arg(0).to_int(); loops = fn.arg(1).to_int(); } s->play_sound(snd, snd->m_id, loops); } } }
// public loadSound(url:String, isStreaming:Boolean) : Void void sound_load(const function_call& fn) { if (fn.nargs > 1) { sound_handler* s = get_sound_handler(); if (s != NULL) { as_sound* snd = cast_to<as_sound>(fn.this_ptr); assert(snd); lfl_string full_url = get_full_url(fn.get_player()->get_workdir(), fn.arg(0).to_string()); int id = s->load_sound(full_url.c_str()); if (id >= 0) { snd->clear(); snd->m_id = id; snd->m_is_loaded_sound = true; } } } }
void sound_volume(const function_call& fn) { if (fn.nargs < 1) { log_error("set volume of sound needs one argument\n"); return; } int volume = fn.arg(0).to_int(); // sanity check if (volume >= 0 && volume <= 100) { sound_handler* s = get_sound_handler(); if (s != NULL) { as_sound* snd = cast_to<as_sound>(fn.this_ptr); assert(snd); s->set_volume(snd->m_id, volume); } } }
void as_netstream::play(const char* url) { switch (m_status) { default: break; case PAUSE: m_status = PLAY; m_decoder.signal(); break; case STOP: { // is path relative ? tu_string infile = get_player()->get_workdir(); if (strstr(url, ":") || url[0] == '/') { infile = ""; } infile += url; m_url = infile; get_root()->add_listener(this); if (open_stream(m_url.c_str()) == true) { sound_handler* sound = get_sound_handler(); if (sound) { sound->attach_aux_streamer(audio_streamer, this); } m_thread = new tu_thread(netstream_server, this); } break; } } }
// it is running in decoder thread bool as_netstream::open_stream(const char* c_url) { // This registers all available file formats and codecs // with the library so they will be used automatically when // a file with the corresponding format/codec is opened // Open video file // The last three parameters specify the file format, buffer size and format parameters; // by simply specifying NULL or 0 we ask libavformat to auto-detect the format // and use a default buffer size if (av_open_input_file(&m_FormatCtx, c_url, NULL, 0, NULL) != 0) { // log_error("Couldn't open file '%s'\n", c_url); set_status(error, playStreamNotFound); return false; } // Next, we need to retrieve information about the streams contained in the file // This fills the streams field of the AVFormatContext with valid information if (av_find_stream_info(m_FormatCtx) < 0) { log_error("Couldn't find stream information from '%s'\n", c_url); return false; } // Find the first video & audio stream m_video_index = -1; m_audio_index = -1; for (int i = 0; i < m_FormatCtx->nb_streams; i++) { AVCodecContext* enc = m_FormatCtx->streams[i]->codec; switch (enc->codec_type) { default: break; case CODEC_TYPE_AUDIO: if (m_audio_index < 0) { m_audio_index = i; m_audio_stream = m_FormatCtx->streams[i]; } break; case CODEC_TYPE_VIDEO: if (m_video_index < 0) { m_video_index = i; m_video_stream = m_FormatCtx->streams[i]; } break; case CODEC_TYPE_DATA: case CODEC_TYPE_SUBTITLE: case CODEC_TYPE_UNKNOWN: break; } } if (m_video_index < 0) { log_error("Didn't find a video stream from '%s'\n", c_url); return false; } // Get a pointer to the codec context for the video stream m_VCodecCtx = m_FormatCtx->streams[m_video_index]->codec; // Find the decoder for the video stream AVCodec* pCodec = avcodec_find_decoder(m_VCodecCtx->codec_id); if (pCodec == NULL) { m_VCodecCtx = NULL; log_error("Decoder not found\n"); return false; } // Open codec if (avcodec_open(m_VCodecCtx, pCodec) < 0) { m_VCodecCtx = NULL; log_error("Could not open codec\n"); return false; } if (m_audio_index >= 0 && get_sound_handler() != NULL) { // Get a pointer to the audio codec context for the video stream m_ACodecCtx = m_FormatCtx->streams[m_audio_index]->codec; // Find the decoder for the audio stream AVCodec* pACodec = avcodec_find_decoder(m_ACodecCtx->codec_id); if (pACodec == NULL) { log_error("No available AUDIO decoder to process MPEG file: '%s'\n", c_url); return false; } // Open codec if (avcodec_open(m_ACodecCtx, pACodec) < 0) { log_error("Could not open AUDIO codec\n"); return false; } } m_convert_ctx = sws_getContext( m_VCodecCtx->width, m_VCodecCtx->height, m_VCodecCtx->pix_fmt, m_VCodecCtx->width, m_VCodecCtx->height, PIX_FMT_RGBA32, SWS_BICUBIC, NULL, NULL, NULL); assert(m_convert_ctx); return true; }
// it is running in decoder thread void as_netstream::run() { set_status(status, playStart); m_start_time = now(); m_video_time = 0; m_status = PLAY; while (m_status == PLAY || m_status == PAUSE) { if (m_status == PAUSE) { double paused = now(); m_decoder.wait(); m_start_time += now() - paused; continue; } // seek request if (m_seek_time >= 0) { int64 timestamp = (int64) (m_seek_time * AV_TIME_BASE); int flags = m_seek_time > m_video_time ? 0 : AVSEEK_FLAG_BACKWARD; int ret = av_seek_frame(m_FormatCtx, -1, timestamp, flags); if (ret == 0) { m_aq.clear(); m_vq.clear(); m_start_time += m_video_time - m_seek_time; m_video_time = m_seek_time; set_status(status, seekNotify); } else { set_status(error, seekInvalidTime); } m_seek_time = -1; } if (get_bufferlength() < m_buffer_time) { //printf("m_buffer_length=%f, queue_size=%d\n", get_bufferlength(), m_vq.size()); AVPacket pkt; int rc = av_read_frame(m_FormatCtx, &pkt); if (rc < 0) { if (m_vq.size() == 0) { break; } } else { if (pkt.stream_index == m_video_index) { m_vq.push(new av_packet(pkt)); } else if (pkt.stream_index == m_audio_index) { if (get_sound_handler()) { m_aq.push(new av_packet(pkt)); } } else { continue; } } } // skip expired video frames double current_time = now() - m_start_time; while (current_time >= m_video_time) { gc_ptr<av_packet> packet; if (m_vq.pop(&packet)) { const AVPacket& pkt = packet->get_packet(); // update video clock with pts, if present if (pkt.dts > 0) { m_video_time = av_q2d(m_video_stream->time_base) * pkt.dts; } m_video_time += av_q2d(m_video_stream->codec->time_base); // +frame_delay set_video_data(decode_video(pkt)); } else { // no packets in queue // set_status("status", "NetStream.Buffer.Empty"); break; } } // Don't hog the CPU. // Queues have filled, video frame have shown // now it is possible and to have a rest int delay = (int) (1000 * (m_video_time - current_time)); // hack, adjust m_start_time after seek if (delay > 50) { m_start_time -= (m_video_time - current_time); current_time = now() - m_start_time; delay = (int) (1000 * (m_video_time - current_time)); } assert(delay <= 50); if (delay > 0) { if (get_bufferlength() >= m_buffer_time) { // set_status("status", "NetStream.Buffer.Full"); tu_timer::sleep(delay); } // printf("current_time=%f, video_time=%f, delay=%d\n", current_time, m_video_time, delay); } } sound_handler* sound = get_sound_handler(); if (sound) { sound->detach_aux_streamer(this); } close_stream(); set_status(status, playStop); m_status = STOP; }