std::unique_ptr<Reply> M4Handler::HandleMessage(Message* message) { SinkMediaManager* sink_media_manager = ToSinkMediaManager(manager_); auto payload = ToPropertyMapPayload(message->payload()); if (!payload) { WDS_ERROR("Failed to obtain payload in M4 handler."); return nullptr; } auto presentation_url = static_cast<rtsp::PresentationUrl*>(payload->GetProperty(rtsp::PresentationURLPropertyType).get()); if (presentation_url) { sink_media_manager->SetPresentationUrl(presentation_url->presentation_url_1()); } auto video_formats = static_cast<rtsp::VideoFormats*>(payload->GetProperty(rtsp::VideoFormatsPropertyType).get()); if (!video_formats) { WDS_ERROR("Failed to obtain 'wfd-video-formats' in M4 handler."); return nullptr; } const auto& selected_formats = video_formats->GetH264Formats(); if (selected_formats.size() != 1) { WDS_ERROR("Failed to obtain optimal video format from 'wfd-video-formats' in M4 handler."); return nullptr; } if (!sink_media_manager->SetOptimalVideoFormat(selected_formats[0])) { auto reply = std::unique_ptr<Reply>(new Reply(rtsp::STATUS_SeeOther)); auto payload = new rtsp::PropertyErrorPayload(); std::vector<unsigned short> error_codes = {rtsp::STATUS_UnsupportedMediaType}; auto property_errors = std::make_shared<rtsp::PropertyErrors>(rtsp::VideoFormatsPropertyType, error_codes); payload->AddPropertyError(property_errors); reply->set_payload(std::unique_ptr<rtsp::Payload>(payload)); return reply; } return std::unique_ptr<Reply>(new Reply(rtsp::STATUS_OK)); }
H264VideoFormat FindOptimalVideoFormat( const NativeVideoFormat& native, const std::vector<H264VideoCodec>& local_codecs, const std::vector<H264VideoCodec>& remote_codecs, bool* success) { std::vector<H264VideoFormat> local_formats, remote_formats; for (const auto& codec : local_codecs) PopulateVideoFormatList(codec, local_formats); for (const auto& codec : remote_codecs) PopulateVideoFormatList(codec, remote_formats); std::sort(local_formats.begin(), local_formats.end(), video_format_sort_func); std::sort(remote_formats.begin(), remote_formats.end(), video_format_sort_func); auto it = local_formats.begin(); auto end = local_formats.end(); H264VideoFormat format(CBP, k3_1, CEA640x480p60); while(it != end) { auto match = std::find( remote_formats.begin(), remote_formats.end(), *it); if (match != remote_formats.end()) { format = *match; break; } ++it; } // Should not happen, 640x480p60 should be always supported! if (it == end) { WDS_ERROR("Failed to find compatible video format."); if (success) *success = false; return format; } // if remote device supports higher codec profile / level // downgrade them to what we support locally. if (format.profile > (*it).profile) format.profile = (*it).profile; if (format.level > (*it).level) format.level = (*it).level; if (success) *success = true; return format; }
std::unique_ptr<Reply> HandleMessage(Message* message) override { auto payload = ToPropertyMapPayload(message->payload()); if (!payload) { WDS_ERROR("Failed to obtain payload in M5 handler."); return nullptr; } auto property = static_cast<rtsp::TriggerMethod*>(payload->GetProperty(rtsp::TriggerMethodPropertyType).get()); auto reply = std::unique_ptr<Reply>(new Reply(rtsp::STATUS_OK)); reply->header().set_cseq(message->cseq()); if (property->method() != rtsp::TriggerMethod::SETUP) { reply->set_response_code(rtsp::STATUS_SeeOther); } return reply; }
int main (int argc, char *argv[]) { InitGlibLogging(); GError *error = NULL; GOptionContext *context; GMainLoop* ml = NULL; gchar* wfd_device_option = NULL; gchar* wfd_stream_option = NULL; gchar* hostname_option = NULL; gint port = 0; GOptionEntry main_entries[] = { { "device", 0, 0, G_OPTION_ARG_STRING, &wfd_device_option, "Specify WFD device type: testsource or sink", "(testsource|sink)"}, { "stream", 0, 0, G_OPTION_ARG_STRING, &wfd_stream_option, "Specify WFD stream type for testsource: audio, video, both or desktop capture", "(audio|video|both|desktop)"}, { "hostname", 0, 0, G_OPTION_ARG_STRING, &hostname_option, "Specify optional hostname or ip address to stream to or listen on", "host"}, { "port", 0, 0, G_OPTION_ARG_INT, &port, "Specify optional UDP port number to stream to or listen on", "port"}, { NULL } }; context = g_option_context_new ("- WFD source/sink demo application\n\nExample:\ngst-test --device=testsource --stream=both --hostname=127.0.0.1 --port=5000\ngst-test --device=sink --port=5000"); g_option_context_add_main_entries (context, main_entries, NULL); if (!g_option_context_parse (context, &argc, &argv, &error)) { WDS_ERROR ("option parsing failed: %s", error->message); g_option_context_free(context); exit (1); } g_option_context_free(context); wfd_test_stream_t wfd_stream = WFD_UNKNOWN_STREAM; if (g_strcmp0(wfd_stream_option, "audio") == 0) wfd_stream = WFD_TEST_AUDIO; else if (g_strcmp0(wfd_stream_option, "video") == 0) wfd_stream = WFD_TEST_VIDEO; else if (g_strcmp0(wfd_stream_option, "both") == 0) wfd_stream = WFD_TEST_BOTH; else if (g_strcmp0(wfd_stream_option, "desktop") == 0) wfd_stream = WFD_DESKTOP; std::string hostname; if (hostname_option) hostname = hostname_option; g_free(wfd_stream_option); g_free(hostname_option); gst_init (&argc, &argv); std::unique_ptr<MiracGstSink> sink_pipeline; std::unique_ptr<MiracGstTestSource> source_pipeline; if (g_strcmp0(wfd_device_option, "testsource") == 0) { source_pipeline.reset(new MiracGstTestSource(wfd_stream, hostname, port)); source_pipeline->SetState(GST_STATE_PLAYING); WDS_LOG("Source UDP port: %d", source_pipeline->UdpSourcePort()); } else if (g_strcmp0(wfd_device_option, "sink") == 0) { sink_pipeline.reset(new MiracGstSink(hostname, port)); WDS_LOG("Listening on port %d", sink_pipeline->sink_udp_port()); } g_free(wfd_device_option); ml = g_main_loop_new(NULL, TRUE); g_unix_signal_add(SIGINT, _sig_handler, ml); g_unix_signal_add(SIGTERM, _sig_handler, ml); g_main_loop_run(ml); g_main_loop_unref(ml); return 0; }