event_t * be_file_playaudio(const char *url, media_pipe_t *mp, char *errbuf, size_t errlen, int hold, const char *mimetype) { AVFormatContext *fctx; AVCodecContext *ctx; AVPacket pkt; media_format_t *fw; int i, r, si; media_buf_t *mb = NULL; media_queue_t *mq; event_ts_t *ets; int64_t ts, seekbase = 0; media_codec_t *cw; event_t *e; int lost_focus = 0; int registered_play = 0; mp_set_playstatus_by_hold(mp, hold, NULL); fa_handle_t *fh = fa_open_ex(url, errbuf, errlen, FA_BUFFERED_SMALL, NULL); if(fh == NULL) return NULL; // First we need to check for a few other formats #if ENABLE_LIBOPENSPC || ENABLE_LIBGME uint8_t pb[128]; size_t psiz; psiz = fa_read(fh, pb, sizeof(pb)); if(psiz < sizeof(pb)) { fa_close(fh); snprintf(errbuf, errlen, "Fill too small"); return NULL; } #if ENABLE_LIBGME if(*gme_identify_header(pb)) return fa_gme_playfile(mp, fh, errbuf, errlen, hold, url); #endif #if ENABLE_LIBOPENSPC if(!memcmp(pb, "SNES-SPC700 Sound File Data", 27)) return openspc_play(mp, fh, errbuf, errlen); #endif #endif AVIOContext *avio = fa_libav_reopen(fh); if(avio == NULL) { fa_close(fh); return NULL; } if((fctx = fa_libav_open_format(avio, url, errbuf, errlen, mimetype)) == NULL) { fa_libav_close(avio); return NULL; } TRACE(TRACE_DEBUG, "Audio", "Starting playback of %s", url); mp_configure(mp, MP_PLAY_CAPS_SEEK | MP_PLAY_CAPS_PAUSE, MP_BUFFER_SHALLOW); mp->mp_audio.mq_stream = -1; mp->mp_video.mq_stream = -1; fw = media_format_create(fctx); cw = NULL; for(i = 0; i < fctx->nb_streams; i++) { ctx = fctx->streams[i]->codec; if(ctx->codec_type != AVMEDIA_TYPE_AUDIO) continue; cw = media_codec_create(ctx->codec_id, 0, fw, ctx, NULL, mp); mp->mp_audio.mq_stream = i; break; } if(cw == NULL) { media_format_deref(fw); snprintf(errbuf, errlen, "Unable to open codec"); return NULL; } mp_become_primary(mp); mq = &mp->mp_audio; while(1) { /** * Need to fetch a new packet ? */ if(mb == NULL) { mp->mp_eof = 0; r = av_read_frame(fctx, &pkt); if(r == AVERROR(EAGAIN)) continue; if(r == AVERROR_EOF || r == AVERROR(EIO)) { mb = MB_SPECIAL_EOF; mp->mp_eof = 1; continue; } if(r != 0) { char msg[100]; fa_ffmpeg_error_to_txt(r, msg, sizeof(msg)); TRACE(TRACE_ERROR, "Audio", "Playback error: %s", msg); while((e = mp_wait_for_empty_queues(mp)) != NULL) { if(event_is_type(e, EVENT_PLAYQUEUE_JUMP) || event_is_action(e, ACTION_PREV_TRACK) || event_is_action(e, ACTION_NEXT_TRACK) || event_is_action(e, ACTION_STOP)) { mp_flush(mp, 0); break; } event_release(e); } if(e == NULL) e = event_create_type(EVENT_EOF); break; } si = pkt.stream_index; if(si != mp->mp_audio.mq_stream) { av_free_packet(&pkt); continue; } mb = media_buf_alloc_unlocked(mp, pkt.size); mb->mb_data_type = MB_AUDIO; mb->mb_pts = rescale(fctx, pkt.pts, si); mb->mb_dts = rescale(fctx, pkt.dts, si); mb->mb_duration = rescale(fctx, pkt.duration, si); mb->mb_cw = media_codec_ref(cw); /* Move the data pointers from ffmpeg's packet */ mb->mb_stream = pkt.stream_index; memcpy(mb->mb_data, pkt.data, pkt.size); if(mb->mb_pts != AV_NOPTS_VALUE) { if(fctx->start_time == AV_NOPTS_VALUE) mb->mb_time = mb->mb_pts; else mb->mb_time = mb->mb_pts - fctx->start_time; } else mb->mb_time = AV_NOPTS_VALUE; mb->mb_send_pts = 1; av_free_packet(&pkt); } /* * Try to send the buffer. If mb_enqueue() returns something we * catched an event instead of enqueueing the buffer. In this case * 'mb' will be left untouched. */ if(mb == MB_SPECIAL_EOF) { // We have reached EOF, drain queues e = mp_wait_for_empty_queues(mp); if(e == NULL) { e = event_create_type(EVENT_EOF); break; } } else if((e = mb_enqueue_with_events(mp, mq, mb)) == NULL) { mb = NULL; /* Enqueue succeeded */ continue; } if(event_is_type(e, EVENT_PLAYQUEUE_JUMP)) { mp_flush(mp, 0); break; } else if(event_is_type(e, EVENT_CURRENT_PTS)) { ets = (event_ts_t *)e; seekbase = ets->ts; if(registered_play == 0) { if(ets->ts - fctx->start_time > METADB_AUDIO_PLAY_THRESHOLD) { registered_play = 1; metadb_register_play(url, 1, CONTENT_AUDIO); } } } else if(event_is_type(e, EVENT_SEEK)) { ets = (event_ts_t *)e; ts = ets->ts + fctx->start_time; if(ts < fctx->start_time) ts = fctx->start_time; av_seek_frame(fctx, -1, ts, AVSEEK_FLAG_BACKWARD); seekflush(mp, &mb); } else if(event_is_action(e, ACTION_SEEK_FAST_BACKWARD)) { av_seek_frame(fctx, -1, seekbase - 60000000, AVSEEK_FLAG_BACKWARD); seekflush(mp, &mb); } else if(event_is_action(e, ACTION_SEEK_BACKWARD)) { av_seek_frame(fctx, -1, seekbase - 15000000, AVSEEK_FLAG_BACKWARD); seekflush(mp, &mb); } else if(event_is_action(e, ACTION_SEEK_FAST_FORWARD)) { av_seek_frame(fctx, -1, seekbase + 60000000, 0); seekflush(mp, &mb); } else if(event_is_action(e, ACTION_SEEK_FORWARD)) { av_seek_frame(fctx, -1, seekbase + 15000000, 0); seekflush(mp, &mb); #if 0 } else if(event_is_action(e, ACTION_RESTART_TRACK)) { av_seek_frame(fctx, -1, 0, AVSEEK_FLAG_BACKWARD); seekflush(mp, &mb); #endif } else if(event_is_action(e, ACTION_PLAYPAUSE) || event_is_action(e, ACTION_PLAY) || event_is_action(e, ACTION_PAUSE)) { hold = action_update_hold_by_event(hold, e); mp_send_cmd_head(mp, mq, hold ? MB_CTRL_PAUSE : MB_CTRL_PLAY); lost_focus = 0; mp_set_playstatus_by_hold(mp, hold, NULL); } else if(event_is_type(e, EVENT_MP_NO_LONGER_PRIMARY)) { hold = 1; lost_focus = 1; mp_send_cmd_head(mp, mq, MB_CTRL_PAUSE); mp_set_playstatus_by_hold(mp, hold, e->e_payload); } else if(event_is_type(e, EVENT_MP_IS_PRIMARY)) { if(lost_focus) { hold = 0; lost_focus = 0; mp_send_cmd_head(mp, mq, MB_CTRL_PLAY); mp_set_playstatus_by_hold(mp, hold, NULL); } } else if(event_is_type(e, EVENT_INTERNAL_PAUSE)) { hold = 1; lost_focus = 0; mp_send_cmd_head(mp, mq, MB_CTRL_PAUSE); mp_set_playstatus_by_hold(mp, hold, e->e_payload); } else if(event_is_action(e, ACTION_PREV_TRACK) || event_is_action(e, ACTION_NEXT_TRACK) || event_is_action(e, ACTION_STOP)) { mp_flush(mp, 0); break; } event_release(e); } if(mb != NULL && mb != MB_SPECIAL_EOF) media_buf_free_unlocked(mp, mb); media_codec_deref(cw); media_format_deref(fw); if(hold) { // If we were paused, release playback again. mp_send_cmd(mp, mq, MB_CTRL_PLAY); mp_set_playstatus_by_hold(mp, 0, NULL); } return e; }
static event_t * openspc_play(media_pipe_t *mp, AVIOContext *avio, char *errbuf, size_t errlen) { media_queue_t *mq = &mp->mp_audio; #error fa_fsize can return -1 .. deal with it size_t r, siz = fa_fsize(fh); uint8_t *buf = malloc(siz); media_buf_t *mb = NULL; event_t *e; int hold = 0, lost_focus = 0; int sample = 0; unsigned int duration = INT32_MAX; mp_set_playstatus_by_hold(mp, hold, NULL); mp->mp_audio.mq_stream = 0; fa_seek(fh, 0, SEEK_SET); r = fa_read(fh, buf, siz); fa_close(fh); if(r != siz) { free(buf); snprintf(errbuf, errlen, "openspc: Unable to read file"); return NULL; } if(OSPC_Init(buf, siz)) { free(buf); snprintf(errbuf, errlen, "openspc: Unable to initialize file"); return NULL; } if(!memcmp("v0.30", buf + 0x1c, 4) && buf[0x23] == 0x1a) { char str[4]; memcpy(str, buf + 0xa9, 3); str[3] = 0; duration = atoi(str) * 32000; } mp_set_play_caps(mp, MP_PLAY_CAPS_PAUSE); mp_become_primary(mp); while(1) { if(mb == NULL) { if(sample > duration) { while((e = mp_wait_for_empty_queues(mp, 0)) != NULL) { if(event_is_type(e, EVENT_PLAYQUEUE_JUMP) || event_is_action(e, ACTION_PREV_TRACK) || event_is_action(e, ACTION_NEXT_TRACK) || event_is_action(e, ACTION_STOP)) { mp_flush(mp, 0); break; } event_release(e); } if(e == NULL) e = event_create_type(EVENT_EOF); break; } mb = media_buf_alloc(); mb->mb_data_type = MB_AUDIO; mb->mb_size = sizeof(int16_t) * 2048 * 2; mb->mb_data = malloc(mb->mb_size); mb->mb_size = OSPC_Run(-1, mb->mb_data, mb->mb_size); mb->mb_channels = 2; mb->mb_rate = 32000; mb->mb_time = sample * 1000000LL / mb->mb_rate; sample += 2048; } if((e = mb_enqueue_with_events(mp, mq, mb)) == NULL) { mb = NULL; /* Enqueue succeeded */ continue; } if(event_is_type(e, EVENT_PLAYQUEUE_JUMP)) { mp_flush(mp, 0); break; } else if(event_is_action(e, ACTION_PLAYPAUSE) || event_is_action(e, ACTION_PLAY) || event_is_action(e, ACTION_PAUSE)) { hold = action_update_hold_by_event(hold, e); mp_send_cmd_head(mp, mq, hold ? MB_CTRL_PAUSE : MB_CTRL_PLAY); lost_focus = 0; mp_set_playstatus_by_hold(mp, hold, NULL); } else if(event_is_type(e, EVENT_MP_NO_LONGER_PRIMARY)) { hold = 1; lost_focus = 1; mp_send_cmd_head(mp, mq, MB_CTRL_PAUSE); mp_set_playstatus_by_hold(mp, hold, e->e_payload); } else if(event_is_type(e, EVENT_MP_IS_PRIMARY)) { if(lost_focus) { hold = 0; lost_focus = 0; mp_send_cmd_head(mp, mq, MB_CTRL_PLAY); mp_set_playstatus_by_hold(mp, hold, NULL); } } else if(event_is_type(e, EVENT_INTERNAL_PAUSE)) { hold = 1; lost_focus = 0; mp_send_cmd_head(mp, mq, MB_CTRL_PAUSE); mp_set_playstatus_by_hold(mp, hold, e->e_payload); } else if(event_is_action(e, ACTION_PREV_TRACK) || event_is_action(e, ACTION_NEXT_TRACK) || event_is_action(e, ACTION_STOP)) { mp_flush(mp, 0); break; } event_release(e); } free(buf); return e; }
static event_t * rtmp_loop(rtmp_t *r, media_pipe_t *mp, char *url, char *errbuf, size_t errlen) { RTMPPacket p = {0}; int pos = -1, ret; uint32_t dts; event_t *e = NULL; mp_set_playstatus_by_hold(mp, 0, NULL); while(1) { if(pos == -1) { mp->mp_eof = 0; ret = RTMP_GetNextMediaPacket(r->r, &p); if(ret == 2) { /* Wait for queues to drain */ mp->mp_eof = 1; again: e = mp_wait_for_empty_queues(mp); if(e != NULL) { e = rtmp_process_event(r, e, NULL); if(e == NULL) goto again; } if(e == NULL) e = event_create_type(EVENT_EOF); break; } if(ret == 0) { int64_t restartpos = r->seekpos_video; TRACE(TRACE_ERROR, "RTMP", "Disconnected"); sleep(1); if(restartpos == AV_NOPTS_VALUE) { snprintf(errbuf, errlen, "Giving up restart since nothing was decoded"); return NULL; } RTMP_Close(r->r); RTMP_Init(r->r); memset(&p, 0, sizeof(p)); TRACE(TRACE_DEBUG, "RTMP", "Reconnecting stream at pos %ld", restartpos); if(!RTMP_SetupURL(r->r, url)) { snprintf(errbuf, errlen, "Unable to setup RTMP session"); return NULL; } if(!RTMP_Connect(r->r, NULL)) { snprintf(errbuf, errlen, "Unable to connect RTMP session"); return NULL; } if(!RTMP_ConnectStream(r->r, 0)) { snprintf(errbuf, errlen, "Unable to stream RTMP session"); return NULL; } if(r->can_seek) RTMP_SendSeek(r->r, restartpos / 1000); continue; } dts = p.m_nTimeStamp; switch(p.m_packetType) { case RTMP_PACKET_TYPE_INFO: if(handle_metadata(r, p.m_body, p.m_nBodySize, mp, errbuf, errlen)) { RTMPPacket_Free(&p); return NULL; } break; case RTMP_PACKET_TYPE_VIDEO: e = get_packet_v(r, (void *)p.m_body, p.m_nBodySize, dts, mp); break; case RTMP_PACKET_TYPE_AUDIO: e = get_packet_a(r, (void *)p.m_body, p.m_nBodySize, dts, mp); break; case 0x16: pos = 0; break; default: TRACE(TRACE_DEBUG, "RTMP", "Got unknown packet type %d\n", p.m_packetType); break; } if(pos == -1) RTMPPacket_Free(&p); } if(pos != -1) { if(pos + 11 < p.m_nBodySize) { uint32_t ds = AMF_DecodeInt24(p.m_body + pos + 1); if(pos + 11 + ds + 4 > p.m_nBodySize) { snprintf(errbuf, errlen, "Corrupt stream"); RTMPPacket_Free(&p); return NULL; } dts = AMF_DecodeInt24(p.m_body + pos + 4); dts |= (p.m_body[pos + 7] << 24); if(p.m_body[pos] == RTMP_PACKET_TYPE_INFO) { if(handle_metadata(r, p.m_body, p.m_nBodySize, mp, errbuf, errlen)) { RTMPPacket_Free(&p); return NULL; } } else if(p.m_body[pos] == RTMP_PACKET_TYPE_VIDEO) { e = get_packet_v(r, (void *)p.m_body + pos + 11, ds, dts, mp); } else if(p.m_body[pos] == RTMP_PACKET_TYPE_AUDIO) { e = get_packet_a(r, (void *)p.m_body + pos + 11, ds, dts, mp); } else { TRACE(TRACE_DEBUG, "RTMP", "Got unknown packet type %d\n", p.m_body[pos]); } pos += 11 + ds + 4; } else { pos = -1; RTMPPacket_Free(&p); } } if(e != NULL) break; } return e; }
/** * Play given track. * * We only expect this to be called from the playqueue system. */ static event_t * be_sid2player_play(const char *url0, media_pipe_t *mp, char *errbuf, size_t errlen, int hold, const char *mimetype) { media_queue_t *mq = &mp->mp_audio; char *url, *p; int sample = 0; media_buf_t *mb = NULL; event_t *e; int subsong; int registered_play = 0; void *player; url0 += strlen("sidplayer:"); url = mystrdupa(url0); p = strrchr(url, '/'); if(p == NULL) { snprintf(errbuf, errlen, "Invalid filename"); return NULL; } *p++= 0; subsong = atoi(p); buf_t *b; if((b = fa_load(url, NULL, errbuf, errlen, NULL, 0, NULL, NULL)) == NULL) return NULL; player = sidcxx_load(b->b_ptr, b->b_size, subsong, errbuf, errlen); buf_release(b); if(player == NULL) return NULL; mp_set_playstatus_by_hold(mp, hold, NULL); mp->mp_audio.mq_stream = 0; mp_configure(mp, MP_PLAY_CAPS_PAUSE, MP_BUFFER_NONE, 0); mp_become_primary(mp); while(1) { if(mb == NULL) { mb = media_buf_alloc_unlocked(mp, sizeof(int16_t) * CHUNK_SIZE * 2); mb->mb_data_type = MB_AUDIO; mb->mb_channels = 2; mb->mb_rate = 44100; mb->mb_pts = sample * 1000000LL / mb->mb_rate; mb->mb_drive_clock = 1; if(!registered_play && mb->mb_pts > METADB_AUDIO_PLAY_THRESHOLD) { registered_play = 1; metadb_register_play(url0, 1, CONTENT_AUDIO); } sample += CHUNK_SIZE; int16_t *samples = mb->mb_data; sidcxx_play(player, samples, CHUNK_SIZE * sizeof(int16_t) * mb->mb_channels); // Crossmix 25% int i, l, r, L, R; for(i = 0; i < CHUNK_SIZE; i++) { l = samples[i * 2 + 0]; r = samples[i * 2 + 1]; L = 3 * l + r * 2; R = 3 * r + l * 2; L = L / 4; R = R / 4; if(L > 32767) L = 32767; if(L < -32768) L = -32768; if(R > 32767) R = 32767; if(R < -32768) R = -32768; samples[i * 2 + 0] = L; samples[i * 2 + 1] = R; } } if((e = mb_enqueue_with_events(mp, mq, mb)) == NULL) { mb = NULL; /* Enqueue succeeded */ continue; } if(event_is_type(e, EVENT_PLAYQUEUE_JUMP)) { mp_flush(mp, 0); break; } else if(event_is_action(e, ACTION_SKIP_BACKWARD) || event_is_action(e, ACTION_SKIP_FORWARD) || event_is_action(e, ACTION_STOP)) { mp_flush(mp, 0); break; } event_release(e); } sidcxx_stop(player); return e; }
static void * test_generator_thread(void *aux) { media_pipe_t *mp = aux; media_buf_t *mb = NULL; event_t *e; media_queue_t *mq = &mp->mp_audio; pcm_sound_t voices[8]; AVFrame *frame = av_frame_alloc(); AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_AC3); AVCodecContext *ctx = avcodec_alloc_context3(codec); ctx->sample_fmt = AV_SAMPLE_FMT_FLTP; ctx->sample_rate = 48000; ctx->channel_layout = AV_CH_LAYOUT_5POINT1; if(avcodec_open2(ctx, codec, NULL) < 0) { TRACE(TRACE_ERROR, "audio", "Unable to open encoder"); return NULL; } float *genbuf[8]; for(int i = 0; i < 8; i++) { genbuf[i] = av_malloc(ctx->frame_size * sizeof(float)); frame->data[i] = (void *)genbuf[i]; } frame->nb_samples = ctx->frame_size; media_codec_t *mc = media_codec_create(AV_CODEC_ID_AC3, 0, NULL, NULL, NULL, mp); mp_set_playstatus_by_hold(mp, 0, NULL); mp->mp_audio.mq_stream = 0; mp_configure(mp, 0, MP_BUFFER_NONE, 0, "testsignal"); mp_become_primary(mp); int sample = 0; unpack_speaker_positions(voices); while(1) { if(mb == NULL) { int got_packet; AVPacket pkt = {0}; generator_t *g; switch(signal_type) { case 0: for(int c = 0; c < 8; c++) { int z = ctx->frame_size; if(test_channels[c]) { int j = sample & 0xffff; int to_copy = MIN(ctx->frame_size, (voices[c].samples - j)); if(to_copy < 0) to_copy = 0; for(int i = 0; i < to_copy; i++) { genbuf[c][i] = voices[c].data[j+i] / 32767.0f; } z = ctx->frame_size - to_copy; } memset(genbuf[c] + ctx->frame_size - z, 0, sizeof(float) * z); } sample += ctx->frame_size; goto encode; default: g = &gen_pink_noise; break; case 2: g = &gen_sinewave; break; } for(int i = 0; i < ctx->frame_size; i++) { float x = g(sample); for(int c = 0; c < 8; c++) { genbuf[c][i] = test_channels[c] ? x : 0; } sample++; } encode: av_init_packet(&pkt); int r = avcodec_encode_audio2(ctx, &pkt, frame, &got_packet); if(!r && got_packet) { mb = media_buf_from_avpkt_unlocked(mp, &pkt); av_free_packet(&pkt); } else { sleep(1); } mb->mb_cw = media_codec_ref(mc); mb->mb_data_type = MB_AUDIO; mb->mb_pts = PTS_UNSET; } if((e = mb_enqueue_with_events(mp, mq, mb)) == NULL) { mb = NULL; /* Enqueue succeeded */ continue; } if(event_is_type(e, EVENT_EXIT)) { mp_flush(mp, 0); break; } event_release(e); } av_frame_free(&frame); for(int i = 0; i < 8; i++) av_freep(&genbuf[i]); for(int i = 0; i < 8; i++) free(voices[i].data); media_codec_deref(mc); return NULL; }
event_t * be_file_playaudio(const char *url, media_pipe_t *mp, char *errbuf, size_t errlen, int hold) { AVFormatContext *fctx; AVIOContext *avio; AVCodecContext *ctx; AVPacket pkt; media_format_t *fw; int i, r, si; media_buf_t *mb = NULL; media_queue_t *mq; event_ts_t *ets; int64_t ts, pts4seek = 0; media_codec_t *cw; event_t *e; int lost_focus = 0; mp_set_playstatus_by_hold(mp, hold, NULL); if((avio = fa_libav_open(url, 32768, errbuf, errlen)) == NULL) return NULL; // First we need to check for a few other formats #if ENABLE_LIBOPENSPC || ENABLE_LIBGME uint8_t pb[128]; size_t psiz; psiz = avio_read(avio, pb, sizeof(pb)); if(psiz < sizeof(pb)) { fa_libav_close(avio); snprintf(errbuf, errlen, "Fill too small"); return NULL; } #if ENABLE_LIBGME if(*gme_identify_header(pb)) return fa_gme_playfile(mp, avio, errbuf, errlen, hold); #endif #if ENABLE_LIBOPENSPC if(!memcmp(pb, "SNES-SPC700 Sound File Data", 27)) return openspc_play(mp, avio, errbuf, errlen); #endif #endif if((fctx = fa_libav_open_format(avio, url, errbuf, errlen)) == NULL) { fa_libav_close(avio); return NULL; } TRACE(TRACE_DEBUG, "Audio", "Starting playback of %s", url); mp_set_play_caps(mp, MP_PLAY_CAPS_SEEK | MP_PLAY_CAPS_PAUSE); mp->mp_audio.mq_stream = -1; mp->mp_video.mq_stream = -1; fw = media_format_create(fctx); cw = NULL; for(i = 0; i < fctx->nb_streams; i++) { ctx = fctx->streams[i]->codec; if(ctx->codec_type != AVMEDIA_TYPE_AUDIO) continue; cw = media_codec_create(ctx->codec_id, 0, fw, ctx, NULL, mp); mp->mp_audio.mq_stream = i; break; } if(cw == NULL) { media_format_deref(fw); snprintf(errbuf, errlen, "Unable to open codec"); return NULL; } mp_become_primary(mp); mq = &mp->mp_audio; while(1) { /** * Need to fetch a new packet ? */ if(mb == NULL) { if((r = av_read_frame(fctx, &pkt)) < 0) { while((e = mp_wait_for_empty_queues(mp, 0)) != NULL) { if(event_is_type(e, EVENT_PLAYQUEUE_JUMP) || event_is_action(e, ACTION_PREV_TRACK) || event_is_action(e, ACTION_NEXT_TRACK) || event_is_action(e, ACTION_STOP)) { mp_flush(mp, 0); break; } event_release(e); } if(e == NULL) e = event_create_type(EVENT_EOF); break; } si = pkt.stream_index; if(si == mp->mp_audio.mq_stream) { /* Current audio stream */ mb = media_buf_alloc(); mb->mb_data_type = MB_AUDIO; } else { /* Check event queue ? */ av_free_packet(&pkt); continue; } mb->mb_pts = rescale(fctx, pkt.pts, si); mb->mb_dts = rescale(fctx, pkt.dts, si); mb->mb_duration = rescale(fctx, pkt.duration, si); mb->mb_cw = media_codec_ref(cw); /* Move the data pointers from ffmpeg's packet */ mb->mb_stream = pkt.stream_index; av_dup_packet(&pkt); mb->mb_data = pkt.data; pkt.data = NULL; mb->mb_size = pkt.size; pkt.size = 0; if(mb->mb_pts != AV_NOPTS_VALUE) { if(fctx->start_time == AV_NOPTS_VALUE) mb->mb_time = mb->mb_pts; else mb->mb_time = mb->mb_pts - fctx->start_time; pts4seek = mb->mb_time; } else mb->mb_time = AV_NOPTS_VALUE; av_free_packet(&pkt); } /* * Try to send the buffer. If mb_enqueue() returns something we * catched an event instead of enqueueing the buffer. In this case * 'mb' will be left untouched. */ if((e = mb_enqueue_with_events(mp, mq, mb)) == NULL) { mb = NULL; /* Enqueue succeeded */ continue; } if(event_is_type(e, EVENT_PLAYQUEUE_JUMP)) { mp_flush(mp, 0); break; } else if(event_is_type(e, EVENT_SEEK)) { ets = (event_ts_t *)e; ts = ets->pts + fctx->start_time; if(ts < fctx->start_time) ts = fctx->start_time; av_seek_frame(fctx, -1, ts, AVSEEK_FLAG_BACKWARD); seekflush(mp, &mb); } else if(event_is_action(e, ACTION_SEEK_FAST_BACKWARD)) { av_seek_frame(fctx, -1, pts4seek - 60000000, AVSEEK_FLAG_BACKWARD); seekflush(mp, &mb); } else if(event_is_action(e, ACTION_SEEK_BACKWARD)) { av_seek_frame(fctx, -1, pts4seek - 15000000, AVSEEK_FLAG_BACKWARD); seekflush(mp, &mb); } else if(event_is_action(e, ACTION_SEEK_FAST_FORWARD)) { av_seek_frame(fctx, -1, pts4seek + 60000000, 0); seekflush(mp, &mb); } else if(event_is_action(e, ACTION_SEEK_FORWARD)) { av_seek_frame(fctx, -1, pts4seek + 15000000, 0); seekflush(mp, &mb); #if 0 } else if(event_is_action(e, ACTION_RESTART_TRACK)) { av_seek_frame(fctx, -1, 0, AVSEEK_FLAG_BACKWARD); seekflush(mp, &mb); #endif } else if(event_is_action(e, ACTION_PLAYPAUSE) || event_is_action(e, ACTION_PLAY) || event_is_action(e, ACTION_PAUSE)) { hold = action_update_hold_by_event(hold, e); mp_send_cmd_head(mp, mq, hold ? MB_CTRL_PAUSE : MB_CTRL_PLAY); lost_focus = 0; mp_set_playstatus_by_hold(mp, hold, NULL); } else if(event_is_type(e, EVENT_MP_NO_LONGER_PRIMARY)) { hold = 1; lost_focus = 1; mp_send_cmd_head(mp, mq, MB_CTRL_PAUSE); mp_set_playstatus_by_hold(mp, hold, e->e_payload); } else if(event_is_type(e, EVENT_MP_IS_PRIMARY)) { if(lost_focus) { hold = 0; lost_focus = 0; mp_send_cmd_head(mp, mq, MB_CTRL_PLAY); mp_set_playstatus_by_hold(mp, hold, NULL); } } else if(event_is_type(e, EVENT_INTERNAL_PAUSE)) { hold = 1; lost_focus = 0; mp_send_cmd_head(mp, mq, MB_CTRL_PAUSE); mp_set_playstatus_by_hold(mp, hold, e->e_payload); } else if(event_is_action(e, ACTION_PREV_TRACK) || event_is_action(e, ACTION_NEXT_TRACK) || event_is_action(e, ACTION_STOP)) { mp_flush(mp, 0); break; } event_release(e); } if(mb != NULL) media_buf_free(mb); media_codec_deref(cw); media_format_deref(fw); if(hold) { // If we were paused, release playback again. mp_send_cmd(mp, mq, MB_CTRL_PLAY); mp_set_playstatus_by_hold(mp, 0, NULL); } return e; }
static event_t * rtmp_process_event(rtmp_t *r, event_t *e, media_buf_t **mbp) { media_pipe_t *mp = r->mp; if(event_is_type(e, EVENT_EXIT) || event_is_type(e, EVENT_PLAY_URL) || event_is_action(e, ACTION_SKIP_FORWARD)) return e; if(event_is_action(e, ACTION_SKIP_BACKWARD)) { if(mp->mp_seek_base < MP_SKIP_LIMIT) { return e; } video_seek(r, mp, mbp, 0, "direct"); } if(event_is_action(e, ACTION_PLAYPAUSE) || event_is_action(e, ACTION_PLAY) || event_is_action(e, ACTION_PAUSE)) { r->hold = action_update_hold_by_event(r->hold, e); mp_send_cmd_head(mp, &mp->mp_video, r->hold ? MB_CTRL_PAUSE : MB_CTRL_PLAY); mp_send_cmd_head(mp, &mp->mp_audio, r->hold ? MB_CTRL_PAUSE : MB_CTRL_PLAY); mp_set_playstatus_by_hold(mp, r->hold, NULL); } else if(event_is_type(e, EVENT_INTERNAL_PAUSE)) { r->hold = 1; mp_send_cmd_head(mp, &mp->mp_video, MB_CTRL_PAUSE); mp_send_cmd_head(mp, &mp->mp_audio, MB_CTRL_PAUSE); mp_set_playstatus_by_hold(mp, r->hold, e->e_payload); } else if(event_is_type(e, EVENT_CURRENT_TIME)) { event_ts_t *ets = (event_ts_t *)e; int sec = ets->ts / 1000000; if(sec != r->restartpos_last && r->can_seek) { r->restartpos_last = sec; metadb_set_video_restartpos(r->canonical_url, mp->mp_seek_base / 1000); } } else if(r->can_seek && event_is_type(e, EVENT_SEEK)) { event_ts_t *ets = (event_ts_t *)e; video_seek(r, mp, mbp, ets->ts, "direct"); } else if(event_is_action(e, ACTION_STOP)) { mp_set_playstatus_stop(mp); } else if(event_is_type(e, EVENT_SELECT_SUBTITLE_TRACK)) { event_select_track_t *est = (event_select_track_t *)e; prop_set_string(mp->mp_prop_subtitle_track_current, est->id); if(!strcmp(est->id, "sub:off")) { mp_load_ext_sub(mp, NULL); } else { mp_load_ext_sub(mp, est->id); } } event_release(e); return NULL; }
/** * Play given track. * * We only expect this to be called from the playqueue system. */ static event_t * be_sid2player_play(const char *url0, media_pipe_t *mp, char *errbuf, size_t errlen, int hold, const char *mimetype) { media_queue_t *mq = &mp->mp_audio; char *url, *p; int sample = 0, lost_focus = 0; media_buf_t *mb = NULL; event_t *e; int subsong; void *player; void *data; struct fa_stat fs; url0 += strlen("sidplayer:"); url = mystrdupa(url0); p = strrchr(url, '/'); if(p == NULL) { snprintf(errbuf, errlen, "Invalid filename"); return NULL; } *p++= 0; subsong = atoi(p); if((data = fa_quickload(url, &fs, NULL, errbuf, errlen)) == NULL) return NULL; player = sidcxx_load(data, fs.fs_size, subsong, errbuf, errlen); free(data); if(player == NULL) return NULL; mp_set_playstatus_by_hold(mp, hold, NULL); mp->mp_audio.mq_stream = 0; mp_configure(mp, MP_PLAY_CAPS_PAUSE, MP_BUFFER_NONE); mp_become_primary(mp); while(1) { if(mb == NULL) { mb = media_buf_alloc(); mb->mb_data_type = MB_AUDIO; mb->mb_channels = 2; mb->mb_size = sizeof(int16_t) * CHUNK_SIZE * mb->mb_channels; mb->mb_data = malloc(mb->mb_size); mb->mb_rate = 44100; mb->mb_time = sample * 1000000LL / mb->mb_rate; sample += CHUNK_SIZE; int16_t *samples = mb->mb_data; sidcxx_play(player, samples, CHUNK_SIZE * sizeof(int16_t) * mb->mb_channels); // Crossmix 25% int i, l, r, L, R; for(i = 0; i < CHUNK_SIZE; i++) { l = samples[i * 2 + 0]; r = samples[i * 2 + 1]; L = 3 * l + r * 2; R = 3 * r + l * 2; L = L / 4; R = R / 4; if(L > 32767) L = 32767; if(L < -32768) L = -32768; if(R > 32767) R = 32767; if(R < -32768) R = -32768; samples[i * 2 + 0] = L; samples[i * 2 + 1] = R; } } if((e = mb_enqueue_with_events(mp, mq, mb)) == NULL) { mb = NULL; /* Enqueue succeeded */ continue; } if(event_is_type(e, EVENT_PLAYQUEUE_JUMP)) { mp_flush(mp, 0); break; } else if(event_is_action(e, ACTION_PLAYPAUSE) || event_is_action(e, ACTION_PLAY) || event_is_action(e, ACTION_PAUSE)) { hold = action_update_hold_by_event(hold, e); mp_send_cmd_head(mp, mq, hold ? MB_CTRL_PAUSE : MB_CTRL_PLAY); lost_focus = 0; mp_set_playstatus_by_hold(mp, hold, NULL); } else if(event_is_type(e, EVENT_MP_NO_LONGER_PRIMARY)) { hold = 1; lost_focus = 1; mp_send_cmd_head(mp, mq, MB_CTRL_PAUSE); mp_set_playstatus_by_hold(mp, hold, e->e_payload); } else if(event_is_type(e, EVENT_MP_IS_PRIMARY)) { if(lost_focus) { hold = 0; lost_focus = 0; mp_send_cmd_head(mp, mq, MB_CTRL_PLAY); mp_set_playstatus_by_hold(mp, hold, NULL); } } else if(event_is_type(e, EVENT_INTERNAL_PAUSE)) { hold = 1; lost_focus = 0; mp_send_cmd_head(mp, mq, MB_CTRL_PAUSE); mp_set_playstatus_by_hold(mp, hold, e->e_payload); } else if(event_is_action(e, ACTION_PREV_TRACK) || event_is_action(e, ACTION_NEXT_TRACK) || event_is_action(e, ACTION_STOP)) { mp_flush(mp, 0); break; } event_release(e); } sidcxx_stop(player); return e; }
static event_t * fa_gme_playfile_internal(media_pipe_t *mp, void *fh, char *errbuf, size_t errlen, int hold, int track) { media_queue_t *mq = &mp->mp_audio; Music_Emu *emu; gme_err_t err; char *buf; int lost_focus = 0; size_t size, r; int sample_rate = 48000; media_buf_t *mb = NULL; event_t *e; size = fa_fsize(fh); buf = malloc(size); r = fa_read(fh, buf, size); if(r != size) { snprintf(errbuf, errlen, "Unable to read file"); free(buf); return NULL; } err = gme_open_data(buf, size, &emu, sample_rate); free(buf); if(err != NULL) { snprintf(errbuf, errlen, "Unable to load file -- %s", err); return NULL; } gme_start_track(emu, track); mp_set_playstatus_by_hold(mp, hold, NULL); mp->mp_audio.mq_stream = 0; mp_set_play_caps(mp, MP_PLAY_CAPS_PAUSE | MP_PLAY_CAPS_SEEK); mp_become_primary(mp); while(1) { if(gme_track_ended(emu)) { e = event_create_type(EVENT_EOF); break; } if(mb == NULL) { mb = media_buf_alloc(); mb->mb_data_type = MB_AUDIO; mb->mb_channels = 2; mb->mb_size = sizeof(int16_t) * CHUNK_SIZE * mb->mb_channels; mb->mb_data = malloc(mb->mb_size); mb->mb_rate = sample_rate; mb->mb_time = gme_tell(emu) * 1000; gme_play(emu, CHUNK_SIZE * mb->mb_channels, mb->mb_data); } if((e = mb_enqueue_with_events(mp, mq, mb)) == NULL) { mb = NULL; /* Enqueue succeeded */ continue; } if(event_is_type(e, EVENT_PLAYQUEUE_JUMP)) { mp_flush(mp, 0); break; } else if(event_is_type(e, EVENT_SEEK)) { event_ts_t *ets = (event_ts_t *)e; gme_seek(emu, ets->pts / 1000); seekflush(mp, &mb); } else if(event_is_action(e, ACTION_SEEK_FAST_BACKWARD)) { deltaseek(mp, &mb, emu, -60000); } else if(event_is_action(e, ACTION_SEEK_BACKWARD)) { deltaseek(mp, &mb, emu, -15000); } else if(event_is_action(e, ACTION_SEEK_FAST_FORWARD)) { deltaseek(mp, &mb, emu, 60000); } else if(event_is_action(e, ACTION_SEEK_FORWARD)) { deltaseek(mp, &mb, emu, 15000); } else if(event_is_action(e, ACTION_PLAYPAUSE) || event_is_action(e, ACTION_PLAY) || event_is_action(e, ACTION_PAUSE)) { hold = action_update_hold_by_event(hold, e); mp_send_cmd_head(mp, mq, hold ? MB_CTRL_PAUSE : MB_CTRL_PLAY); lost_focus = 0; mp_set_playstatus_by_hold(mp, hold, NULL); } else if(event_is_type(e, EVENT_MP_NO_LONGER_PRIMARY)) { hold = 1; lost_focus = 1; mp_send_cmd_head(mp, mq, MB_CTRL_PAUSE); mp_set_playstatus_by_hold(mp, hold, e->e_payload); } else if(event_is_type(e, EVENT_MP_IS_PRIMARY)) { if(lost_focus) { hold = 0; lost_focus = 0; mp_send_cmd_head(mp, mq, MB_CTRL_PLAY); mp_set_playstatus_by_hold(mp, hold, NULL); } } else if(event_is_type(e, EVENT_INTERNAL_PAUSE)) { hold = 1; lost_focus = 0; mp_send_cmd_head(mp, mq, MB_CTRL_PAUSE); mp_set_playstatus_by_hold(mp, hold, e->e_payload); } else if(event_is_action(e, ACTION_PREV_TRACK) || event_is_action(e, ACTION_NEXT_TRACK) || event_is_action(e, ACTION_STOP)) { mp_flush(mp, 0); break; } event_release(e); } gme_delete(emu); if(mb != NULL) media_buf_free(mb); if(hold) { // If we were paused, release playback again. mp_send_cmd(mp, mq, MB_CTRL_PLAY); mp_set_playstatus_by_hold(mp, 0, NULL); } return e; }
static event_t * rtmp_process_event(rtmp_t *r, event_t *e, media_buf_t **mbp) { media_pipe_t *mp = r->mp; if(event_is_type(e, EVENT_EXIT) || event_is_type(e, EVENT_PLAY_URL)) return e; if(event_is_action(e, ACTION_PLAYPAUSE) || event_is_action(e, ACTION_PLAY) || event_is_action(e, ACTION_PAUSE)) { r->hold = action_update_hold_by_event(r->hold, e); mp_send_cmd_head(mp, &mp->mp_video, r->hold ? MB_CTRL_PAUSE : MB_CTRL_PLAY); mp_send_cmd_head(mp, &mp->mp_audio, r->hold ? MB_CTRL_PAUSE : MB_CTRL_PLAY); mp_set_playstatus_by_hold(mp, r->hold, NULL); r->lost_focus = 0; } else if(event_is_type(e, EVENT_MP_NO_LONGER_PRIMARY)) { r->hold = 1; r->lost_focus = 1; mp_send_cmd_head(mp, &mp->mp_video, MB_CTRL_PAUSE); mp_send_cmd_head(mp, &mp->mp_audio, MB_CTRL_PAUSE); mp_set_playstatus_by_hold(mp, r->hold, e->e_payload); } else if(event_is_type(e, EVENT_MP_IS_PRIMARY)) { if(r->lost_focus) { r->hold = 0; r->lost_focus = 0; mp_send_cmd_head(mp, &mp->mp_video, MB_CTRL_PLAY); mp_send_cmd_head(mp, &mp->mp_audio, MB_CTRL_PLAY); mp_set_playstatus_by_hold(mp, r->hold, NULL); } } else if(event_is_type(e, EVENT_INTERNAL_PAUSE)) { r->hold = 1; r->lost_focus = 0; mp_send_cmd_head(mp, &mp->mp_video, MB_CTRL_PAUSE); mp_send_cmd_head(mp, &mp->mp_audio, MB_CTRL_PAUSE); mp_set_playstatus_by_hold(mp, r->hold, e->e_payload); } else if(event_is_type(e, EVENT_CURRENT_PTS)) { event_ts_t *ets = (event_ts_t *)e; r->seekbase = ets->ts; int sec = r->seekbase / 1000000; if(sec != r->restartpos_last && r->can_seek) { r->restartpos_last = sec; metadb_set_video_restartpos(r->canonical_url, r->seekbase / 1000); } } else if(r->can_seek && event_is_type(e, EVENT_SEEK)) { event_ts_t *ets = (event_ts_t *)e; r->epoch++; r->seekbase = video_seek(r, mp, mbp, ets->ts, 1, "direct"); } else if(r->can_seek && event_is_action(e, ACTION_SEEK_FAST_BACKWARD)) { r->seekbase = video_seek(r, mp, mbp, r->seekbase - 60000000, 1, "-60s"); } else if(r->can_seek && event_is_action(e, ACTION_SEEK_BACKWARD)) { r->seekbase = video_seek(r, mp, mbp, r->seekbase - 15000000, 1, "-15s"); } else if(r->can_seek && event_is_action(e, ACTION_SEEK_FORWARD)) { r->seekbase = video_seek(r, mp, mbp, r->seekbase + 15000000, 1, "+15s"); } else if(r->can_seek && event_is_action(e, ACTION_SEEK_FAST_FORWARD)) { r->seekbase = video_seek(r, mp, mbp, r->seekbase + 60000000, 1, "+60s"); } else if(event_is_action(e, ACTION_STOP)) { mp_set_playstatus_stop(mp); } else if(event_is_type(e, EVENT_SELECT_SUBTITLE_TRACK)) { event_select_track_t *est = (event_select_track_t *)e; prop_set_string(mp->mp_prop_subtitle_track_current, est->id); if(!strcmp(est->id, "sub:off")) { mp_load_ext_sub(mp, NULL); } else { mp_load_ext_sub(mp, est->id); } } event_release(e); return NULL; }
static event_t * rtmp_loop(rtmp_t *r, media_pipe_t *mp, char *url, char *errbuf, size_t errlen) { RTMPPacket p = {0}; int pos = -1, ret; uint32_t dts; event_t *e = NULL; r->mp = mp; r->hold = 0; r->lost_focus = 0; r->epoch = 1; r->seekbase = AV_NOPTS_VALUE; r->seekpos = AV_NOPTS_VALUE; r->subpts = AV_NOPTS_VALUE; r->lastsubpts = AV_NOPTS_VALUE; mp->mp_video.mq_seektarget = AV_NOPTS_VALUE; mp->mp_audio.mq_seektarget = AV_NOPTS_VALUE; mp_set_playstatus_by_hold(mp, 0, NULL); while(1) { if(pos == -1) { ret = RTMP_GetNextMediaPacket(r->r, &p); if(ret == 2) { /* Wait for queues to drain */ e = mp_wait_for_empty_queues(mp, 0); mp_set_playstatus_stop(mp); if(e == NULL) e = event_create_type(EVENT_EOF); break; } if(ret == 0) { RTMP_Close(r->r); RTMP_Init(r->r); memset(&p, 0, sizeof(p)); TRACE(TRACE_DEBUG, "RTMP", "Reconnecting stream at pos %d", r->seekbase); if(!RTMP_SetupURL(r->r, url)) { snprintf(errbuf, errlen, "Unable to setup RTMP session"); e = NULL; break; } if(!RTMP_Connect(r->r, NULL)) { snprintf(errbuf, errlen, "Unable to connect RTMP session"); e = NULL; break; } if(!RTMP_ConnectStream(r->r, r->seekbase / 1000)) { snprintf(errbuf, errlen, "Unable to stream RTMP session"); return NULL; } r->epoch++; r->lastdts = 0; r->seekbase = AV_NOPTS_VALUE; mp_flush(mp, 0); continue; } dts = p.m_nTimeStamp; switch(p.m_packetType) { case RTMP_PACKET_TYPE_INFO: if(handle_metadata(r, p.m_body, p.m_nBodySize, mp, errbuf, errlen)) { RTMPPacket_Free(&p); return NULL; } break; case RTMP_PACKET_TYPE_VIDEO: e = get_packet_v(r, (void *)p.m_body, p.m_nBodySize, dts, mp); break; case RTMP_PACKET_TYPE_AUDIO: e = get_packet_a(r, (void *)p.m_body, p.m_nBodySize, dts, mp); break; case 0x16: pos = 0; break; default: TRACE(TRACE_DEBUG, "RTMP", "Got unknown packet type %d\n", p.m_packetType); break; } if(pos == -1) RTMPPacket_Free(&p); } if(pos != -1) { if(pos + 11 < p.m_nBodySize) { uint32_t ds = AMF_DecodeInt24(p.m_body + pos + 1); if(pos + 11 + ds + 4 > p.m_nBodySize) { snprintf(errbuf, errlen, "Corrupt stream"); RTMPPacket_Free(&p); return NULL; } dts = AMF_DecodeInt24(p.m_body + pos + 4); dts |= (p.m_body[pos + 7] << 24); if(p.m_body[pos] == RTMP_PACKET_TYPE_INFO) { if(handle_metadata(r, p.m_body, p.m_nBodySize, mp, errbuf, errlen)) { RTMPPacket_Free(&p); return NULL; } } else if(p.m_body[pos] == RTMP_PACKET_TYPE_VIDEO) { e = get_packet_v(r, (void *)p.m_body + pos + 11, ds, dts, mp); } else if(p.m_body[pos] == RTMP_PACKET_TYPE_AUDIO) { e = get_packet_a(r, (void *)p.m_body + pos + 11, ds, dts, mp); } else { TRACE(TRACE_DEBUG, "RTMP", "Got unknown packet type %d\n", p.m_body[pos]); } pos += 11 + ds + 4; } else { pos = -1; RTMPPacket_Free(&p); } } if(e != NULL) break; } return e; }
static event_t * rtmp_process_event(rtmp_t *r, event_t *e, media_buf_t **mbp) { media_pipe_t *mp = r->mp; if(event_is_type(e, EVENT_EXIT) || event_is_type(e, EVENT_PLAY_URL)) return e; if(event_is_action(e, ACTION_PLAYPAUSE) || event_is_action(e, ACTION_PLAY) || event_is_action(e, ACTION_PAUSE)) { r->hold = action_update_hold_by_event(r->hold, e); mp_send_cmd_head(mp, &mp->mp_video, r->hold ? MB_CTRL_PAUSE : MB_CTRL_PLAY); mp_send_cmd_head(mp, &mp->mp_audio, r->hold ? MB_CTRL_PAUSE : MB_CTRL_PLAY); mp_set_playstatus_by_hold(mp, r->hold, NULL); r->lost_focus = 0; } else if(event_is_type(e, EVENT_MP_NO_LONGER_PRIMARY)) { r->hold = 1; r->lost_focus = 1; mp_send_cmd_head(mp, &mp->mp_video, MB_CTRL_PAUSE); mp_send_cmd_head(mp, &mp->mp_audio, MB_CTRL_PAUSE); mp_set_playstatus_by_hold(mp, r->hold, e->e_payload); } else if(event_is_type(e, EVENT_MP_IS_PRIMARY)) { if(r->lost_focus) { r->hold = 0; r->lost_focus = 0; mp_send_cmd_head(mp, &mp->mp_video, MB_CTRL_PLAY); mp_send_cmd_head(mp, &mp->mp_audio, MB_CTRL_PLAY); mp_set_playstatus_by_hold(mp, r->hold, NULL); } } else if(event_is_type(e, EVENT_INTERNAL_PAUSE)) { r->hold = 1; r->lost_focus = 0; mp_send_cmd_head(mp, &mp->mp_video, MB_CTRL_PAUSE); mp_send_cmd_head(mp, &mp->mp_audio, MB_CTRL_PAUSE); mp_set_playstatus_by_hold(mp, r->hold, e->e_payload); } else if(event_is_type(e, EVENT_CURRENT_PTS)) { event_ts_t *ets = (event_ts_t *)e; r->seekbase = ets->pts; } else if(event_is_type(e, EVENT_SEEK)) { event_ts_t *ets = (event_ts_t *)e; r->epoch++; r->seekbase = video_seek(r, mp, mbp, ets->pts, 1, "direct"); } else if(event_is_action(e, ACTION_SEEK_FAST_BACKWARD)) { r->seekbase = video_seek(r, mp, mbp, r->seekbase - 60000000, 1, "-60s"); } else if(event_is_action(e, ACTION_SEEK_BACKWARD)) { r->seekbase = video_seek(r, mp, mbp, r->seekbase - 15000000, 1, "-15s"); } else if(event_is_action(e, ACTION_SEEK_FORWARD)) { r->seekbase = video_seek(r, mp, mbp, r->seekbase + 15000000, 1, "+15s"); } else if(event_is_action(e, ACTION_SEEK_FAST_FORWARD)) { r->seekbase = video_seek(r, mp, mbp, r->seekbase + 60000000, 1, "+60s"); } else if(event_is_action(e, ACTION_STOP)) { mp_set_playstatus_stop(mp); } else if(event_is_type(e, EVENT_SELECT_TRACK)) { event_select_track_t *est = (event_select_track_t *)e; prop_set_string(mp->mp_prop_subtitle_track_current, est->id); if(r->sub != NULL) subtitles_destroy(r->sub); r->sub = subtitles_load(est->id); } event_release(e); return NULL; }
static event_t * fa_gme_playfile_internal(media_pipe_t *mp, void *buf, size_t size, char *errbuf, size_t errlen, int hold, int track, const char *url) { media_queue_t *mq = &mp->mp_audio; Music_Emu *emu; gme_err_t err; int sample_rate = 48000; media_buf_t *mb = NULL; event_t *e; int registered_play = 0; err = gme_open_data(buf, size, &emu, sample_rate); if(err != NULL) { snprintf(errbuf, errlen, "Unable to load file -- %s", err); return NULL; } gme_start_track(emu, track); mp_set_playstatus_by_hold(mp, hold, NULL); mp->mp_audio.mq_stream = 0; mp_configure(mp, MP_PLAY_CAPS_PAUSE | MP_PLAY_CAPS_SEEK, MP_BUFFER_SHALLOW); mp_become_primary(mp); while(1) { if(gme_track_ended(emu)) { e = event_create_type(EVENT_EOF); break; } if(mb == NULL) { mb = media_buf_alloc_unlocked(mp, sizeof(int16_t) * CHUNK_SIZE * 2); mb->mb_data_type = MB_AUDIO; mb->mb_channels = 2; mb->mb_rate = sample_rate; mb->mb_time = gme_tell(emu) * 1000; if(!registered_play && mb->mb_time > METADB_AUDIO_PLAY_THRESHOLD) { registered_play = 1; metadb_register_play(url, 1, CONTENT_AUDIO); } gme_play(emu, CHUNK_SIZE * mb->mb_channels, mb->mb_data); } if((e = mb_enqueue_with_events(mp, mq, mb)) == NULL) { mb = NULL; /* Enqueue succeeded */ continue; } if(event_is_type(e, EVENT_PLAYQUEUE_JUMP)) { mp_flush(mp, 0); break; } else if(event_is_type(e, EVENT_SEEK)) { event_ts_t *ets = (event_ts_t *)e; gme_seek(emu, ets->ts / 1000); seekflush(mp, &mb); } else if(event_is_action(e, ACTION_PLAYPAUSE) || event_is_action(e, ACTION_PLAY) || event_is_action(e, ACTION_PAUSE)) { hold = action_update_hold_by_event(hold, e); mp_send_cmd_head(mp, mq, hold ? MB_CTRL_PAUSE : MB_CTRL_PLAY); mp_set_playstatus_by_hold(mp, hold, NULL); } else if(event_is_type(e, EVENT_INTERNAL_PAUSE)) { hold = 1; mp_send_cmd_head(mp, mq, MB_CTRL_PAUSE); mp_set_playstatus_by_hold(mp, hold, e->e_payload); } else if(event_is_action(e, ACTION_SKIP_BACKWARD) || event_is_action(e, ACTION_SKIP_FORWARD) || event_is_action(e, ACTION_STOP)) { mp_flush(mp, 0); break; } event_release(e); } gme_delete(emu); if(mb != NULL) media_buf_free_unlocked(mp, mb); if(hold) { // If we were paused, release playback again. mp_send_cmd(mp, mq, MB_CTRL_PLAY); mp_set_playstatus_by_hold(mp, 0, NULL); } return e; }