static int handle_metadata0(rtmp_t *r, AMFObject *obj, media_pipe_t *mp, char *errstr, size_t errlen) { AVal metastring; AMFObjectProperty prop; prop_t *m = mp->mp_prop_metadata; AMFProp_GetString(AMF_GetProp(obj, NULL, 0), &metastring); if(!AVMATCH(&metastring, &av_onMetaData)) { snprintf(errstr, errlen, "No metadata in metadata packet"); return -1; } if(RTMP_FindFirstMatchingProperty(obj, &av_duration, &prop) && prop.p_type == AMF_NUMBER && prop.p_vu.p_number > 0) { prop_set_float(prop_create(m, "duration"), prop.p_vu.p_number); r->total_duration = prop.p_vu.p_number * 1000; mp_set_duration(mp, r->total_duration * 1000LL); mp_set_clr_flags(mp, MP_CAN_SEEK, 0); if(r->ss == NULL && !(r->va->flags & BACKEND_VIDEO_NO_SUBTITLE_SCAN)) r->ss = sub_scanner_create(r->url, mp->mp_prop_subtitle_tracks, r->va, 0); } else { r->total_duration = 0; mp_set_duration(mp, AV_NOPTS_VALUE); mp_set_clr_flags(mp, 0, MP_CAN_SEEK); } if((RTMP_FindFirstMatchingProperty(obj, &av_videoframerate, &prop) && RTMP_FindFirstMatchingProperty(obj, &av_framerate, &prop)) && prop.p_type == AMF_NUMBER) { r->vframeduration = 1000000.0 / prop.p_vu.p_number; mp->mp_framerate.num = 1000000; mp->mp_framerate.den = prop.p_vu.p_number; } r->width = r->height = 0; if(RTMP_FindFirstMatchingProperty(obj, &av_width, &prop) && prop.p_type == AMF_NUMBER) r->width = prop.p_vu.p_number; if(RTMP_FindFirstMatchingProperty(obj, &av_height, &prop) && prop.p_type == AMF_NUMBER) r->height = prop.p_vu.p_number; if(r->width && r->height) TRACE(TRACE_DEBUG, "RTMP", "Video size %d x %d", r->width, r->height); return 0; }
static event_t * rtmp_playvideo(const char *url0, media_pipe_t *mp, char *errbuf, size_t errlen, video_queue_t *vq, struct vsource_list *vsl, const video_args_t *va0) { video_args_t va = *va0; rtmp_t r = {0}; event_t *e; char *url = mystrdupa(url0); va.flags |= BACKEND_VIDEO_NO_FS_SCAN; prop_set_string(mp->mp_prop_type, "video"); rtmp_log_level = RTMP_LOGINFO; RTMP_LogSetLevel(rtmp_log_level); r.r = RTMP_Alloc(); RTMP_Init(r.r); int64_t start = 0; if(va.flags & BACKEND_VIDEO_RESUME || (video_settings.resume_mode == VIDEO_RESUME_YES && !(va.flags & BACKEND_VIDEO_START_FROM_BEGINNING))) start = video_get_restartpos(va.canonical_url); if(!RTMP_SetupURL(r.r, url)) { snprintf(errbuf, errlen, "Unable to setup RTMP-session"); rtmp_free(&r); return NULL; } r.r->Link.lFlags |= RTMP_LF_SWFV; if(!RTMP_Connect(r.r, NULL)) { snprintf(errbuf, errlen, "Unable to connect RTMP-session"); rtmp_free(&r); return NULL; } if(!RTMP_ConnectStream(r.r, 0)) { snprintf(errbuf, errlen, "Unable to connect RTMP-stream"); rtmp_free(&r); return NULL; } if(start) RTMP_SendSeek(r.r, start); r.mp = mp; mp->mp_audio.mq_stream = 0; mp->mp_video.mq_stream = 0; if(start > 0) { r.seekpos_video = start * 1000; r.seekpos_audio = start * 1000; mp->mp_seek_base = r.seekpos_video; mp->mp_video.mq_seektarget = r.seekpos_video; mp->mp_audio.mq_seektarget = r.seekpos_video; } else { mp->mp_video.mq_seektarget = AV_NOPTS_VALUE; mp->mp_audio.mq_seektarget = AV_NOPTS_VALUE; mp->mp_seek_base = 0; r.seekpos_audio = AV_NOPTS_VALUE; r.seekpos_video = AV_NOPTS_VALUE; } mp_configure(mp, MP_PLAY_CAPS_PAUSE, MP_BUFFER_DEEP, 0); mp->mp_max_realtime_delay = (r.r->Link.timeout - 1) * 1000000; mp_become_primary(mp); metadb_register_play(va.canonical_url, 0, CONTENT_VIDEO); r.canonical_url = va.canonical_url; r.restartpos_last = -1; sub_scanner_t *ss = sub_scanner_create(url, mp->mp_prop_subtitle_tracks, &va, 0); e = rtmp_loop(&r, mp, url, errbuf, errlen); sub_scanner_destroy(ss); if(r.total_duration) { int p = mp->mp_seek_base / (r.total_duration * 10); if(p >= video_settings.played_threshold) { TRACE(TRACE_DEBUG, "RTMP", "Playback reached %d%%, counting as played", p); metadb_register_play(va.canonical_url, 1, CONTENT_VIDEO); metadb_set_video_restartpos(va.canonical_url, -1); } } mp_flush(mp, 0); mp_shutdown(mp); TRACE(TRACE_DEBUG, "RTMP", "End of stream"); rtmp_free(&r); return e; }