├── README.md ├── wasm_player_sample ├── widget │ ├── styles.css │ ├── index.html │ └── emss_loader.js ├── LICENSE ├── src │ ├── main.cc │ ├── sample_data.h │ ├── emss_sdf_sample.h │ └── emss_sdf_sample.cc └── README.md ├── video_decoder_sample ├── widget │ ├── styles.css │ ├── index.html │ └── emss_loader.js ├── LICENSE ├── src │ ├── main.cc │ ├── sample_data.h │ ├── video_decoder_sdf_sample.h │ ├── emss_sdf_sample.h │ ├── video_decoder_sdf_sample.cc │ └── emss_sdf_sample.cc └── README.md ├── sample_curl_app_built_with_cli ├── config.xml ├── COPYING ├── url2file.c └── README.md └── sample_curl_app_built_with_tizen_studio ├── COPYING ├── url2file_side_thread.cpp └── README.md /README.md: -------------------------------------------------------------------------------- 1 | # WebAssembly demos 2 | 3 | Repository contains sample applications showing usage of Tizen Extensions 4 | for WebAssembly. 5 | 6 | Applications from this repository are used in WebAssembly guides on 7 | [Samsung Developers](https://developer.samsung.com/smarttv/develop/extension-libraries/webassembly/overview.html) 8 | site. 9 | -------------------------------------------------------------------------------- /wasm_player_sample/widget/styles.css: -------------------------------------------------------------------------------- 1 | 2 | body { 3 | width: 100vw; 4 | height: 100vh; 5 | margin: 0; 6 | padding: 0; 7 | background-color: #1a1a1a; 8 | color: #cbcddb; 9 | } 10 | 11 | #video-element { 12 | width: 1920px; 13 | height: 1080px; 14 | } 15 | 16 | .centered { 17 | position: absolute; 18 | left: 50%; 19 | top: 50%; 20 | transform: translate(-50%, -50%); 21 | } 22 | 23 | .error { 24 | color: #da4949; 25 | } 26 | 27 | .invisible { 28 | display: none; 29 | } 30 | -------------------------------------------------------------------------------- /video_decoder_sample/widget/styles.css: -------------------------------------------------------------------------------- 1 | 2 | body { 3 | width: 100vw; 4 | height: 100vh; 5 | margin: 0; 6 | padding: 0; 7 | background-color: #1a1a1a; 8 | color: #cbcddb; 9 | } 10 | 11 | #video-element { 12 | width: 0; 13 | height: 0; 14 | } 15 | 16 | .centered { 17 | position: absolute; 18 | left: 50%; 19 | top: 50%; 20 | transform: translate(-50%, -50%); 21 | } 22 | 23 | .copyrights { 24 | position: absolute; 25 | left: 50%; 26 | top: 95%; 27 | transform: translate(-50%, -50%); 28 | } 29 | 30 | .error { 31 | color: #da4949; 32 | } 33 | 34 | .invisible { 35 | display: none; 36 | } 37 | -------------------------------------------------------------------------------- /wasm_player_sample/widget/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Tizen WASM Player - Elementary Media Stream Source SDF Sample 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |

16 |

WASM module is loading...

17 |
18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /video_decoder_sample/widget/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Tizen WASM Video Decoder SDF Sample 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |

17 |

WASM module is loading...

18 |
19 | 20 |
21 |

(c) copyright 2008, Blender Foundation / www.bigbuckbunny.org

22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /sample_curl_app_built_with_cli/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | * 13 | Sample curl (url2file) using Tizen Sockets with Emscripten 14 | 15 | url2file 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /wasm_player_sample/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 Samsung Electronics Inc. 2 | Licensed under the MIT license. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | -------------------------------------------------------------------------------- /video_decoder_sample/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 Samsung Electronics Inc. 2 | Licensed under the MIT license. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | -------------------------------------------------------------------------------- /sample_curl_app_built_with_cli/COPYING: -------------------------------------------------------------------------------- 1 | COPYRIGHT AND PERMISSION NOTICE 2 | 3 | Copyright (c) 1996 - 2020, Daniel Stenberg, , and many 4 | contributors, see the THANKS file. 5 | 6 | All rights reserved. 7 | 8 | Permission to use, copy, modify, and distribute this software for any purpose 9 | with or without fee is hereby granted, provided that the above copyright 10 | notice and this permission notice appear in all copies. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN 15 | NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 17 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 18 | OR OTHER DEALINGS IN THE SOFTWARE. 19 | 20 | Except as contained in this notice, the name of a copyright holder shall not 21 | be used in advertising or otherwise to promote the sale, use or other dealings 22 | in this Software without prior written authorization of the copyright holder. 23 | -------------------------------------------------------------------------------- /sample_curl_app_built_with_tizen_studio/COPYING: -------------------------------------------------------------------------------- 1 | COPYRIGHT AND PERMISSION NOTICE 2 | 3 | Copyright (c) 1996 - 2020, Daniel Stenberg, , and many 4 | contributors, see the THANKS file. 5 | 6 | All rights reserved. 7 | 8 | Permission to use, copy, modify, and distribute this software for any purpose 9 | with or without fee is hereby granted, provided that the above copyright 10 | notice and this permission notice appear in all copies. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN 15 | NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 17 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 18 | OR OTHER DEALINGS IN THE SOFTWARE. 19 | 20 | Except as contained in this notice, the name of a copyright holder shall not 21 | be used in advertising or otherwise to promote the sale, use or other dealings 22 | in this Software without prior written authorization of the copyright holder. 23 | -------------------------------------------------------------------------------- /wasm_player_sample/src/main.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Samsung Electronics Inc. 2 | // Licensed under the MIT license. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | // SOFTWARE. 21 | 22 | // *** Sample Tizen WASM Player Application *** 23 | // 24 | // This file contains startup function for Tizen WASM Player sample 25 | // application. 26 | 27 | #include 28 | 29 | #include "emss_sdf_sample.h" 30 | 31 | static SamplePlayer kSamplePlayerInstance; 32 | 33 | int main() { 34 | // WASM module execution will not terminate when main exits. 35 | EM_ASM(noExitRuntime = true); 36 | 37 | // Start SamplePlayer. 38 | kSamplePlayerInstance.SetUp( 39 | samsung::wasm::ElementaryMediaStreamSource::RenderingMode::kMediaElement); 40 | } 41 | -------------------------------------------------------------------------------- /video_decoder_sample/src/main.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Samsung Electronics Inc. 2 | // Licensed under the MIT license. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | // SOFTWARE. 21 | 22 | // *** Sample Tizen WASM Video Decoder Application *** 23 | // 24 | // This file contains startup function for Tizen WASM Video Decoder sample 25 | // application. 26 | 27 | #include 28 | 29 | #include "video_decoder_sdf_sample.h" 30 | 31 | static VideoDecoderSamplePlayer kSamplePlayerInstance; 32 | 33 | int main() { 34 | // WASM module execution will not terminate when main exits. 35 | EM_ASM(noExitRuntime = true); 36 | 37 | // Start VideoDecoderSamplePlayer. 38 | kSamplePlayerInstance.SetUp( 39 | samsung::wasm::ElementaryMediaStreamSource::RenderingMode::kVideoTexture); 40 | } 41 | -------------------------------------------------------------------------------- /video_decoder_sample/src/sample_data.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Samsung Electronics Inc. 2 | // Licensed under the MIT license. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | // SOFTWARE. 21 | 22 | #ifndef SAMPLE_DATA_H_ 23 | #define SAMPLE_DATA_H_ 24 | 25 | #include 26 | 27 | #include "samsung/wasm/elementary_media_packet.h" 28 | #include "samsung/wasm/elementary_video_track_config.h" 29 | 30 | namespace sample_data { 31 | 32 | // Duration of a stream. 33 | // 34 | // Usually it wouldn't be hardcoded but read from a stream source. Please note 35 | // duration is applicable only in some ElementaryMediaStreamSource modes (see 36 | // samsung::wasm::ElementaryMediaStreamSource::Mode). 37 | extern const samsung::wasm::Seconds kStreamDuration; 38 | 39 | // Contains video track configuration. 40 | // 41 | // Usually it wouldn't be hardcoded but read from a stream source. 42 | extern const samsung::wasm::ElementaryVideoTrackConfig kVideoTrackConfig; 43 | 44 | // Contains Elementary Media Packets of the sample video track. 45 | // 46 | // Usually those wouldn't be hardcoded but either demuxed from a container or 47 | // received from network (depending on the use case and protocol used by an 48 | // application). 49 | extern const std::array 50 | kVideoPackets; 51 | 52 | } // namespace sample_data 53 | 54 | #endif // SAMPLE_DATA_H_ 55 | -------------------------------------------------------------------------------- /wasm_player_sample/src/sample_data.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Samsung Electronics Inc. 2 | // Licensed under the MIT license. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | // SOFTWARE. 21 | 22 | #ifndef SAMPLE_DATA_H_ 23 | #define SAMPLE_DATA_H_ 24 | 25 | #include 26 | 27 | #include "samsung/wasm/elementary_media_packet.h" 28 | #include "samsung/wasm/elementary_video_track_config.h" 29 | 30 | namespace sample_data { 31 | 32 | // Duration of a stream. 33 | // 34 | // Usually it wouldn't be hardcoded but read from a stream source. Please note 35 | // duration is applicable only in some ElementaryMediaStreamSource modes (see 36 | // samsung::wasm::ElementaryMediaStreamSource::Mode). 37 | extern const samsung::wasm::Seconds kStreamDuration; 38 | 39 | // Contains video track configuration. 40 | // 41 | // Usually it wouldn't be hardcoded but read from a stream source. 42 | extern const samsung::wasm::ElementaryVideoTrackConfig kVideoTrackConfig; 43 | 44 | // Contains Elementary Media Packets of the sample video track. 45 | // 46 | // Usually those wouldn't be hardcoded but either demuxed from a container or 47 | // received from network (depending on the use case and protocol used by an 48 | // application). 49 | extern const std::array 50 | kVideoPackets; 51 | 52 | } // namespace sample_data 53 | 54 | #endif // SAMPLE_DATA_H_ 55 | -------------------------------------------------------------------------------- /sample_curl_app_built_with_cli/url2file.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * _ _ ____ _ 3 | * Project ___| | | | _ \| | 4 | * / __| | | | |_) | | 5 | * | (__| |_| | _ <| |___ 6 | * \___|\___/|_| \_\_____| 7 | * 8 | * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. 9 | * 10 | * This software is licensed as described in the file COPYING, which 11 | * you should have received as part of this distribution. The terms 12 | * are also available at https://curl.haxx.se/docs/copyright.html. 13 | * 14 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 | * copies of the Software, and permit persons to whom the Software is 16 | * furnished to do so, under the terms of the COPYING file. 17 | * 18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 | * KIND, either express or implied. 20 | * 21 | ***************************************************************************/ 22 | /* 23 | * Download a given URL into a local file named page.out. 24 | * 25 | */ 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | 32 | static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream) 33 | { 34 | size_t written = fwrite(ptr, size, nmemb, (FILE *)stream); 35 | return written; 36 | } 37 | 38 | /* Demo based on https://curl.haxx.se/libcurl/c/url2file.html 39 | * Changes: 40 | * - file contents are copied to stdout (printed) instad of writing to the file 41 | * - url is set in a source code instead of read from command line 42 | * - cacert.pem file path is set. 43 | */ 44 | int main(int argc, char *argv[]) 45 | { 46 | CURL *curl_handle; 47 | 48 | curl_global_init(CURL_GLOBAL_ALL); 49 | 50 | /* init the curl session */ 51 | curl_handle = curl_easy_init(); 52 | 53 | /* set URL to get here */ 54 | curl_easy_setopt(curl_handle, CURLOPT_URL, "https://example.com"); 55 | 56 | /* Switch on full protocol/debug output while testing */ 57 | curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L); 58 | 59 | /* disable progress meter, set to 0L to enable it */ 60 | curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L); 61 | 62 | /* send all data to this function */ 63 | curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data); 64 | 65 | curl_easy_setopt(curl_handle, CURLOPT_CAINFO, "./cacert.pem"); 66 | 67 | /* write the page body to this file handle */ 68 | curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, stdout); 69 | 70 | /* get it! */ 71 | curl_easy_perform(curl_handle); 72 | 73 | /* cleanup curl stuff */ 74 | curl_easy_cleanup(curl_handle); 75 | 76 | curl_global_cleanup(); 77 | 78 | return 0; 79 | } 80 | -------------------------------------------------------------------------------- /sample_curl_app_built_with_tizen_studio/url2file_side_thread.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * _ _ ____ _ 3 | * Project ___| | | | _ \| | 4 | * / __| | | | |_) | | 5 | * | (__| |_| | _ <| |___ 6 | * \___|\___/|_| \_\_____| 7 | * 8 | * Copyright (C) 1998 - 2019, Daniel Stenberg, , et al. 9 | * 10 | * This software is licensed as described in the file COPYING, which 11 | * you should have received as part of this distribution. The terms 12 | * are also available at https://curl.haxx.se/docs/copyright.html. 13 | * 14 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 | * copies of the Software, and permit persons to whom the Software is 16 | * furnished to do so, under the terms of the COPYING file. 17 | * 18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 | * KIND, either express or implied. 20 | * 21 | ***************************************************************************/ 22 | /* 23 | * Download a given URL into a local file named page.out. 24 | * 25 | */ 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | 32 | #include 33 | 34 | static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream) 35 | { 36 | size_t written = fwrite(ptr, size, nmemb, (FILE *)stream); 37 | return written; 38 | } 39 | 40 | void hello_curl() 41 | { 42 | CURL *curl_handle; 43 | 44 | curl_global_init(CURL_GLOBAL_ALL); 45 | 46 | /* init the curl session */ 47 | curl_handle = curl_easy_init(); 48 | 49 | /* set URL to get here */ 50 | curl_easy_setopt(curl_handle, CURLOPT_URL, "https://example.com"); 51 | 52 | /* Switch on full protocol/debug output while testing */ 53 | curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L); 54 | 55 | /* disable progress meter, set to 0L to enable it */ 56 | curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L); 57 | 58 | /* send all data to this function */ 59 | curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data); 60 | 61 | curl_easy_setopt(curl_handle, CURLOPT_CAINFO, "./cacert.pem"); 62 | 63 | /* write the page body to this file handle */ 64 | curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, stdout); 65 | 66 | /* get it! */ 67 | curl_easy_perform(curl_handle); 68 | 69 | /* cleanup curl stuff */ 70 | curl_easy_cleanup(curl_handle); 71 | 72 | curl_global_cleanup(); 73 | } 74 | 75 | /* Demo based on https://curl.haxx.se/libcurl/c/url2file.html 76 | * Changes: 77 | * - file contents are copied to stdout (printed) instad of writing to the file 78 | * - url is set in a source code instead of read from command line 79 | * - cacert.pem file path is set. 80 | * - download is run in side-thread not directly in main due to restrictions 81 | * of Tizen WebAssembly Sockets API 82 | */ 83 | int main(int argc, char* argv[]) { 84 | std::thread th(hello_curl); 85 | th.join(); 86 | return 0; 87 | } 88 | -------------------------------------------------------------------------------- /video_decoder_sample/src/video_decoder_sdf_sample.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Samsung Electronics Inc. 2 | // Licensed under the MIT license. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | // SOFTWARE. 21 | 22 | // *** Sample Tizen WASM Video Decoder Application *** 23 | // 24 | // This file contains sample implementation of a simple WASM module that decodes 25 | // video content using Tizen WASM Player with ElementaryMediaStreamSource as 26 | // a data source and renders it on `canvas` HTML element using GL. 27 | // The sample uses hardcoded data (see sample_data.h). 28 | 29 | #ifndef VIDEO_DECODER_SAMPLE_VIDEO_DECODER_SDF_SAMPLE_H 30 | #define VIDEO_DECODER_SAMPLE_VIDEO_DECODER_SDF_SAMPLE_H 31 | 32 | #include "emss_sdf_sample.h" 33 | 34 | #include 35 | #include 36 | 37 | // This class is responsible for sending elementary media data to Elementary 38 | // Media Stream Source via ElementaryMediaTrack object. 39 | class VideoDecoderTrackDataPump : public TrackDataPump { 40 | public: 41 | using ElementaryMediaTrack = samsung::wasm::ElementaryMediaTrack; 42 | using Seconds = samsung::wasm::Seconds; 43 | using SessionId = samsung::wasm::SessionId; 44 | 45 | explicit VideoDecoderTrackDataPump(ElementaryMediaTrack video_track); 46 | 47 | ~VideoDecoderTrackDataPump() override = default; 48 | 49 | void OnDrawCompleted(); 50 | void RequestNewVideoTexture(); 51 | 52 | private: 53 | void CreateGLObjects(); 54 | void CreateProgram(); 55 | void Draw(); 56 | void InitializeSDL(); 57 | void InitializeGL(); 58 | 59 | GLuint texture_{0}; 60 | SDL_Window* window_{nullptr}; 61 | SDL_GLContext gl_context_{nullptr}; 62 | GLuint program_{0}; 63 | GLuint texcoord_scale_location_{0}; 64 | }; // class VideoDecoderTrackDataPump 65 | 66 | class VideoDecoderSamplePlayer : public SamplePlayer { 67 | public: 68 | using ElementaryMediaStreamSource = 69 | samsung::wasm::ElementaryMediaStreamSource; 70 | using HTMLMediaElement = samsung::html::HTMLMediaElement; 71 | using Seconds = samsung::wasm::Seconds; 72 | 73 | VideoDecoderSamplePlayer() = default; 74 | 75 | // samsung::wasm::ElementaryMediaStreamSourceListener interface // 76 | void OnCanPlay() override; 77 | 78 | private: 79 | std::unique_ptr CreateTrackDataPump( 80 | ElementaryMediaTrack&& video_track) override; 81 | }; // class VideoDecoderSamplePlayer 82 | 83 | #endif // VIDEO_DECODER_SAMPLE_VIDEO_DECODER_SDF_SAMPLE_H 84 | -------------------------------------------------------------------------------- /wasm_player_sample/widget/emss_loader.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Samsung Electronics Inc. 2 | // Licensed under the MIT license. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | // SOFTWARE. 21 | 22 | // eslint-disable-next-line no-var, no-unused-vars 23 | var Module = undefined; 24 | 25 | // Loads a WASM module. moduleScriptUrl should point to a JS loader script 26 | // generated by Emscripten. 27 | // 28 | // This function loads modules with no MODULARIZE option. 29 | function loadWasmModule(moduleScriptUrl) { 30 | return new Promise((resolve, reject) => { 31 | try { 32 | // This variable will be used by a loader script generated by Emscripten. 33 | Module = { 34 | onRuntimeInitialized: () => { 35 | console.info('WASM runtime initialized'); 36 | resolve(); 37 | }, 38 | onAbort: () => { 39 | console.error('WASM runtime aborted'); 40 | reject(new Error('WASM runtime aborted')); 41 | }, 42 | onExit: (status) => { 43 | console.info(`WASM onExit called with status: ${status}`); 44 | }, 45 | }; // Module 46 | 47 | const script = document.createElement('script'); 48 | 49 | script.addEventListener('load', () => { 50 | console.info(`Loaded ${moduleScriptUrl}`); 51 | }); 52 | 53 | script.addEventListener('error', (errorEvent) => { 54 | console.error(`Cannot load ${moduleScriptUrl}`); 55 | reject(new Error( 56 | `Cannot load ${moduleScriptUrl} error: ${errorEvent.message}`)); 57 | }); 58 | 59 | script.async = true; 60 | script.src = moduleScriptUrl; 61 | document.body.appendChild(script); 62 | } catch (err) { 63 | console.error(err); 64 | reject(new Error('Cannot instantiate WASM module!')); 65 | } 66 | }); 67 | } // loadWasmModule() 68 | 69 | window.addEventListener('DOMContentLoaded', async () => { 70 | const wasmLoadingDiv = document.getElementById('wasm-loading'); 71 | try { 72 | await loadWasmModule( 73 | 'wasm_modules/EMSSSampleModule/CurrentBin/EMSSSampleModule.js'); 74 | } catch (ex) { 75 | wasmLoadingDiv.innerHTML = '

Cannot load WASM module.

'; 76 | return; 77 | } 78 | 79 | const videoElement = document.getElementById('video-element'); 80 | videoElement.requestFullscreen(); 81 | wasmLoadingDiv.classList.add('invisible'); 82 | videoElement.classList.remove('invisible'); 83 | }); // DOMContentLoaded handler 84 | -------------------------------------------------------------------------------- /video_decoder_sample/widget/emss_loader.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Samsung Electronics Inc. 2 | // Licensed under the MIT license. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | // SOFTWARE. 21 | 22 | // eslint-disable-next-line no-var, no-unused-vars 23 | var Module = undefined; 24 | 25 | // Loads a WASM module. moduleScriptUrl should point to a JS loader script 26 | // generated by Emscripten. 27 | // 28 | // This function loads modules with no MODULARIZE option. 29 | function loadWasmModule(moduleScriptUrl) { 30 | return new Promise((resolve, reject) => { 31 | try { 32 | // This variable will be used by a loader script generated by Emscripten. 33 | Module = { 34 | onRuntimeInitialized: () => { 35 | console.info('WASM runtime initialized'); 36 | resolve(); 37 | }, 38 | onAbort: () => { 39 | console.error('WASM runtime aborted'); 40 | reject(new Error('WASM runtime aborted')); 41 | }, 42 | onExit: (status) => { 43 | console.info(`WASM onExit called with status: ${status}`); 44 | }, 45 | canvas: (function() { 46 | var canvas = document.getElementById('canvas'); 47 | return canvas; 48 | })(), 49 | }; // Module 50 | 51 | const script = document.createElement('script'); 52 | 53 | script.addEventListener('load', () => { 54 | console.info(`Loaded ${moduleScriptUrl}`); 55 | }); 56 | 57 | script.addEventListener('error', (errorEvent) => { 58 | console.error(`Cannot load ${moduleScriptUrl}`); 59 | reject(new Error( 60 | `Cannot load ${moduleScriptUrl} error: ${errorEvent.message}`)); 61 | }); 62 | 63 | script.async = true; 64 | script.src = moduleScriptUrl; 65 | document.body.appendChild(script); 66 | } catch (err) { 67 | console.error(err); 68 | reject(new Error('Cannot instantiate WASM module!')); 69 | } 70 | }); 71 | } // loadWasmModule() 72 | 73 | window.addEventListener('DOMContentLoaded', async () => { 74 | const wasmLoadingDiv = document.getElementById('wasm-loading'); 75 | try { 76 | await loadWasmModule( 77 | 'wasm_modules/VideoDecoderSampleModule/CurrentBin/VideoDecoderSampleModule.js'); 78 | } catch (ex) { 79 | wasmLoadingDiv.innerHTML = '

Cannot load WASM module.

'; 80 | return; 81 | } 82 | 83 | const videoElement = document.getElementById('video-element'); 84 | wasmLoadingDiv.classList.add('invisible'); 85 | videoElement.classList.remove('invisible'); 86 | }); // DOMContentLoaded handler 87 | -------------------------------------------------------------------------------- /sample_curl_app_built_with_cli/README.md: -------------------------------------------------------------------------------- 1 | # sample_curl_app_built_with_cli 2 | 3 | Sample application based on 4 | [url2file](https://curl.haxx.se/libcurl/c/url2file.html) 5 | cURL demo built using command-line tools (CLI). 6 | 7 | ## Prerequisites 8 | 9 | - Downloaded [Emscripten toolchain modified by Samsung](https://developer.samsung.com/smarttv/develop/extension-libraries/webassembly/download.html) and activated. 10 | 11 | ## Compilation 12 | 13 | 1. Download [CA certificates extracted from Mozilla](https://curl.haxx.se/docs/caextract.html) : 14 | 15 | ```bash 16 | curl -O https://curl.haxx.se/ca/cacert.pem 17 | ``` 18 | 19 | 2. Compile [url2file.c](./url2file.c) demo 20 | 21 | ```bash 22 | emcc -o url2file.html -Os -s ENVIRONMENT_MAY_BE_TIZEN -s USE_CURL=1 --proxy-to-worker --preload-file cacert.pem url2file.c 23 | ``` 24 | 25 | | Option | Description | 26 | | -------- | ------------------------------------------------------------ | 27 | | `-Os` | Reduce size of generated WebAssembly module. This will reduce memory consumption of WebAssembly module compilation on Samsung Smart TV. | 28 | | `-o url2file.html` | Name of the output, this will make that Emscripten will generate url2file.wasm, url2file.js and url2file.html | 29 | | `-s ENVIRONMENT_MAY_BE_TIZEN` | Flag indicating that we want to use Samsung Tizen Emscripten extensions available on Samsung Smart TV. This flag is necessary to use POSIX sockets APIs in your application. | 30 | | `-s USE_CURL=1` | Flag indicating that we want to build and use cURL library provided with Samsung Customized Emscripten. Note that during 1st build full library is being built, so compilation may take a while. However after 1st build cURL library is cached. See more on details on [Emscripten Ports](https://emscripten.org/docs/compiling/Building-Projects.html#emscripten-ports) | 31 | | `--proxy-to-worker` | This flag is needed to run `main()` function of your application in a Web Worker, because Samsung Tizen Sockets Extensions can only be used in a Web Worker. | 32 | | `--preload-file cacert.pem` | This option allows your application to read cacert.pem file using standard C APIs `fopen(./cacert.pem)` | 33 | 34 | Implicitly enabled options: 35 | 36 | | Option | Description | 37 | | -------- | ------------------------------------------------------------ | 38 | | `-s USE_SSL=1` | Flag enabling SSL library (libssl) from OpenSSL libraries. This flags is implicitly turned on by `-s USE_CURL=1` | 39 | | `-s USE_CRYPTO=1` | Flag enabling use crypto library (libcrypto) from OpenSSL libraries. This flags is implicitly turned on by `-s USE_SSL=1` | 40 | | `-s USE_ZLIB=1` | Flag enabling use of zlib compression library. This flag is implicitly turned on by `-s USE_CURL=1` | 41 | 42 | Further information regarding Emscripten build options can be found on 43 | [Emscripten Compiler Frontend (emcc)](https://emscripten.org/docs/tools_reference/emcc.html#emccdoc) 44 | 45 | 3. Sign and pack widget using Tizen CLI interface: 46 | 47 | ```bash 48 | tizen package -t wgt -s -- . 49 | ```` 50 | 51 | Guide showing how to create certificate profile can be found at [Creating Certificates](https://developer.samsung.com/SmartTV/develop/getting-started/setting-up-sdk/creating-certificates.html) 52 | 53 | More information regarding Tizen CLI interface can be found at [Command Line Interface Commands](https://developer.tizen.org/development/tizen-studio/web-tools/cli) 54 | 55 | *Note:* 56 | This application needs `http://tizen.org/privilege/internet` privilege, as 57 | defined in provided [config.xml](./config.xml) file. 58 | More information regarding the config.xml file format can be found on 59 | [Developer Samsung](https://developer.tizen.org/ko/development/tizen-studio/web-tools/configuring-your-app/configuration-editor?langredirect=1) 60 | 61 | 4. Set your TV into developer mode as described in 62 | [TV Device](https://developer.samsung.com/SmartTV/develop/getting-started/using-sdk/tv-device.html) 63 | 64 | 5. Connect to the TV using sdb: 65 | 66 | ```bash 67 | sdb connect 68 | ``` 69 | 70 | SDB command and its options are described on [Connecting Devices over Smart Development Bridge](https://developer.tizen.org/development/tizen-studio/web-tools/running-and-testing-your-app/sdb) 71 | 72 | 6. List connected devices: 73 | 74 | ```bash 75 | sdb devices 76 | ``` 77 | 78 | Sample output: 79 | 80 | ```bash 81 | List of devices attached 82 | 192.168.13.2:26101 device 0 83 | ``` 84 | 85 | 7. Install widget on the TV: 86 | 87 | ```bash 88 | tizen install -n url2file.wgt -t 0 89 | ``` 90 | 91 | *Note:* 92 | In option `-t 0` value `0` is taken from last column of `sdb devices` 93 | command output. 94 | 95 | 8. Run widget on the TV: 96 | 97 | ```bash 98 | tizen run -p url2file00.curl -t 0 99 | ``` 100 | -------------------------------------------------------------------------------- /wasm_player_sample/README.md: -------------------------------------------------------------------------------- 1 | # Tizen WASM Player - Sample Application 2 | 3 | *Table of Contents:* 4 | * [Introduction](#introduction) 5 | * [Building the sample widget with Tizen Studio](#building-the-sample-widget-with-tizen-studio) 6 | * [Prerequisites](#prerequisites) 7 | * [Step-by-step guide](#step-by-step-guide) 8 | * [Required Emscripten flags](#required-emscripten-flags) 9 | 10 | ## Introduction 11 | 12 | This is a sample application showing how to use **[Tizen WASM Player](https://developer.samsung.com/smarttv/develop/extension-libraries/webassembly/tizen-wasm-player/overview.html)** 13 | to play media on a Samsung Smart TV device using a WebAssembly module. 14 | 15 | The sample application's features are: 16 | * elementary media stream playback using `HTMLMediaElement` with an 17 | `ElementaryMediaStreamSource` data source ([Normal Latency mode](https://developer.samsung.com/smarttv/develop/extension-libraries/webassembly/tizen-wasm-player/overview.html#normal-latency)), 18 | * [looping video](https://developer.samsung.com/smarttv/develop/extension-libraries/webassembly/tizen-wasm-player/wasm-player-usage-guide.html#loop), 19 | * implementation of [Seeking](https://developer.samsung.com/smarttv/develop/extension-libraries/webassembly/tizen-wasm-player/wasm-player-usage-guide.html#seek) and [Multitasking](https://developer.samsung.com/SmartTV/develop/guides/fundamentals/multitasking.html). 20 | 21 | Packetized data is hardcoded in app to maximize data access simplicity. 22 | 23 | ## Building the sample widget with Tizen Studio 24 | 25 | ### Prerequisites 26 | 27 | Emscripten SDK with Samsung extensions and Tizen Studio are required to build 28 | this sample. Please follow [a guide on Samsung Developers](https://developer.samsung.com/smarttv/develop/extension-libraries/webassembly/getting-started/downloading-and-installing.html) 29 | to learn more about their installation and setup. 30 | 31 | ### Step-by-step guide 32 | 33 | 1. Launch Tizen Studio. 34 | 35 | 2. Create a new WebAssembly-enabled project in Tizen Studio: 36 | * File -> New -> Tizen Project, 37 | * select 'Template' and click 'Next', 38 | * select 'TV' and click 'Next', 39 | * select 'Web Application', check 'WebAssembly (C/C++)' box and click 'Next', 40 | * select 'Empty' application template and click 'Next', 41 | * name the project `EMSSSample` and click 'Next', 42 | * enter paths to the Emscripten configuration file and cache directory 43 | (please refer to [a guide on Tizen Developers](https://developer.samsung.com/smarttv/develop/extension-libraries/webassembly/getting-started/creating-hello-webassembly-tv-application.html) 44 | for details), 45 | * click 'Finish'. 46 | 47 | 3. Add a new WebAssembly module to the project: 48 | * click right mouse button on the project in 'Project Explorer', 49 | * click 'New' -> 'WebAssembly Module' in the context menu, 50 | * select 'Empty module' and click 'Next', 51 | * name the module `EMSSSampleModule` (name is important, as this is the name 52 | used to load the module), 53 | * click 'Finish'. 54 | 55 | 4. Replace default HTML5 and C++ files generated by Tizen Studio with the files 56 | from this sample: 57 | 58 | a. Remove generated HTML5 and C++ files: 59 | * `EMSSSample/index.html` 60 | * `EMSSSample/main.js` 61 | * `EMSSSample/css/style.css` 62 | * `EMSSSampleModule/inc/empty.hpp` 63 | * `EMSSSampleModule/src/empty.cpp` 64 | 65 | b. Copy sample widget's files to the projects in Tizen Studio: 66 | * `elementary_media_stream_source_sample/widget/*` -> `EMSSSample/` 67 | * `elementary_media_stream_source_sample/src/*` -> `EMSSSampleModule/` 68 | 69 | 5. Add necessary compiler and linker flags to the WebAssembly module: 70 | * click right mouse button on the `EMSSSampleModule` project in 'Project 71 | Explorer', 72 | * select 'Properties' from the context menu, 73 | * select 'C/C++ Build' -> 'Settings', 74 | * on 'Tool Settings' tab: 75 | * select 'Emscripten C++ Compiler' -> 'Miscellaneous' and edit 'Other 76 | flags', changing `-std=gnu++11` to `-std=gnu++14`, 77 | * select 'Emscripten C++ Linker' -> 'Miscellaneous': 78 | * append following flags to 'Linker flags': 79 | ```bash 80 | -s ENVIRONMENT_MAY_BE_TIZEN -pthread -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=1 81 | ``` 82 | *(flags are explained below, in* Required Emscripten flags *section)* 83 | * remove `-s EXPORT_NAME=EMSSSampleModule -s MODULARIZE=1 ` from 84 | 'Linker flags'. 85 | *Please note:* this step is required, because code loading 86 | modularized and non-modularized WebAssembly modules differ slightly. 87 | This sample is prepared to load modules that doesn't use 88 | `MODULARIZE` option. 89 | * click 'Apply and Close'. 90 | 91 | 6. Build the project: 92 | * click right mouse button on the `EMSSSample` project in 'Project Explorer', 93 | * click 'Build Project' in context menu. 94 | 95 | 7. Create a widget package: 96 | * click right mouse button on the `EMSSSample` project in 'Project Explorer', 97 | * click 'Build Signed Package' in context menu. 98 | 99 | 8. The widget is ready to use! 100 | 101 | ## Required Emscripten flags 102 | 103 | The table below explains Emscripten-specific build flags required to build this 104 | sample: 105 | 106 | | Flag | Description | 107 | |------|-------------| 108 | | `-s ENVIRONMENT_MAY_BE_TIZEN` | Enables usage of Samsung Tizen Emscripten extensions available on Samsung Tizen TVs. This flag is necessary to use Elementary Media Stream Source. | 109 | | `-pthread -s USE_PTHREADS=1` | Enables usage of threads in WebAssembly module. | 110 | | `-s PTHREAD_POOL_SIZE=1` | WebAssembly module will be prepared to start indicated number of threads. It's important to set this parameter to a maximum number of threads that an application uses; otherwise starting new threads may fail! See [pthreads](https://emscripten.org/docs/porting/pthreads.html) in Emscripten documentation for more information. | 111 | -------------------------------------------------------------------------------- /sample_curl_app_built_with_tizen_studio/README.md: -------------------------------------------------------------------------------- 1 | # sample_curl_app_built_with_tizen_studio 2 | 3 | Sample application based on 4 | [url2file](https://curl.haxx.se/libcurl/c/url2file.html) 5 | cURL demo built using Tizen Studio. 6 | 7 | ## Prerequisites 8 | 9 | - Tizen Studio installed and configured according to the [Getting Started](https://developer.samsung.com/smarttv/develop/extension-libraries/webassembly/getting-started.html) guide. 10 | 11 | ## Building 12 | 13 | 1. Launch Tizen Studio. 14 | 15 | 2. Create a project in Tizen Studio: 16 | 17 | - File -> New -> Tizen Project 18 | - Select 'Template' and click 'Next' 19 | - Select 'TV' and click 'Next' 20 | - Select 'Web Application', check 'WebAssembly (C/C++)' box and click 'Next' 21 | - Select 'Empty Project' and click 'Next' 22 | - Give a name to your project (eg. HelloCURL) and click 'Next' 23 | - Provide required Emscripten toolchain paths and click 'Finish' 24 | 25 | 3. Add `http://tizen.org/privilege/internet` privilege to your application. 26 | See [Configuring TV Applications](https://developer.samsung.com/smarttv/develop/guides/fundamentals/configuring-tv-applications.html) guide how to do this. 27 | 28 | 4. Add a new WebAssembly module to your project: 29 | 30 | - Right click on your project in 'Project Explorer' 31 | - From the context menu select 'New' -> 'WebAssembly Module' 32 | - Choose 'Empty module' and click 'Next' 33 | - Give a name to your module (e.g. HelloCURL_module) 34 | - Add 'TextArea' by selecting 'On' checkbox. Logs written to stdout 35 | by the WebAssembly module will be displayed on this 'TextArea'. 36 | - Click 'Finish' 37 | 38 | 5. Either replace contents of `src/empty.cpp` file in the created WebAssembly 39 | module with contents of 40 | [url2file_side_thread.cpp](./url2file_side_thread.cpp) or just copy this 41 | file to the `src/` directory and delete the `src/empty.cpp` file. 42 | 43 | 6. Download [CA certificates extracted from Mozilla](https://curl.haxx.se/ca/cacert.pem) 44 | and save it in the main directory of the WebAssembly module project. 45 | 46 | 7. Add necessary compiler flag to your WebAssembly module: 47 | 48 | - Right click on your WebAssembly module project 49 | - Select 'Properties' from the context menu 50 | - Select 'C/C++ Build' -> 'Settings' 51 | - On 'Tool Settings' tab select 'Emscripten C++ compiler' -> 'Optimization' 52 | - Select 'Level -Os' as 'Optimization level' 53 | - On 'Tool Settings' tab select 'Emscripten C++ compiler' -> 'Miscellaneous' 54 | - Append following flag to 'Other flags': 55 | 56 | ```bash 57 | -s USE_CURL=1 58 | ``` 59 | 60 | This flag `-s USE_CURL=1` is required here and in linker flags below. 61 | As a compiler flag it is required to have cURL include dirs populated and 62 | provided to compilation stage (using `-I` switch). Also putting this flag 63 | here will allow indexer to see cURL include directories and properly 64 | resolve cURL includes. 65 | 66 | 8. Add necessary linker flags to your WebAssembly module: 67 | 68 | - Right click on your WebAssembly module project 69 | - Select 'Properties' from the context menu 70 | - Select 'C/C++ Build' -> 'Settings' 71 | - On 'Tool Settings' tab select 'Emscripten C++ linker' -> 'Miscellaneous' 72 | - Append following flags to 'Linker flags': 73 | 74 | ```bash 75 | -Os -s ENVIRONMENT_MAY_BE_TIZEN -s USE_CURL=1 --preload-file ../cacert.pem@/cacert.pem -pthread -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=2 76 | ``` 77 | 78 | Flags description: 79 | 80 | | Flag | Description | 81 | | -------- | ------------ | 82 | | `-Os` | Reduce size of generated WebAssembly module. This will reduce memory consumption of WebAssembly module compilation on Samsung Smart TV. This flag is required as both compile and link time flag. | 83 | | `-s ENVIRONMENT_MAY_BE_TIZEN` | flag indicating that we want to use Samsung Tizen Emscripten extensions available on Samsung Tizen TVs. This flag is necessary to use POSIX sockets APIs in your application. | 84 | | `-s USE_CURL=1` | flag indicating that we want to build and use cURL library provided with Samsung modified Tizen Emscripten toolchain. Note that during 1st build full library is being built, so compilation may take a while. However after 1st build cURL library is cached. See more on details on [Emscripten Ports](https://emscripten.org/docs/compiling/Building-Projects.html#emscripten-ports) | 85 | | `--preload-file ../cacert.pem@/cacert.pem` | this option allows your application to read the cacert.pem file using standard C APIs `fopen(./cacert.pem)`. Tizen Studio launches Emscripten toolchain in a `CurrentBin` directory, however we have the `cacert.pem` file in main project's directory. To avoid copying this file we use relative path. To refer to this file as `/cacert.pem` in C/C++ program we use mapping `@/cacert.pem` as described in [Modifying file locations in the virtual file system](https://emscripten.org/docs/porting/files/packaging_files.html#modifying-file-locations-in-the-virtual-file-system) | 86 | `-pthread -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=2` | this options allow to use threads in WebAssembly module. Note that it is necessary to call POSIX sockets APIs in threads other than main thread of your application. | 87 | 88 | 9. Build your WebAssembly module project. 89 | 90 | 10. Apply following workarounds: 91 | 92 | 1. Unlink the WebAssembly module from main application. Right click on 93 | main app, then in 'Others' -> 'Project References' unselect referenced 94 | WebAssembly module project. 95 | 96 | 2. While being on project properties add *.data file to the WGT package, 97 | in 'Tizen Studio' -> 'Package' expand tree to 'CurrentBin' directory 98 | of the WebAssembly module project and check file with `data` extension. 99 | Click 'Apply and Close'. Note this particular step must be performed 100 | after each build of the WebAssembly module project. 101 | 102 | 3. Add following snippet to `wasm_modules/scripts/wasm_tools.js` after 103 | the body `print` method: 104 | 105 | ```javascript 106 | locateFile: ( () => { 107 | return (path, prefix) => { 108 | if (prefix == '') { 109 | prefix = this.path.substring(0, this.path.lastIndexOf('/')) || ''; 110 | prefix = prefix + '/'; 111 | } 112 | return prefix + path; 113 | }; 114 | })(), 115 | ``` 116 | 117 | 11. Build signed package. 118 | 119 | 12. Now you're done you can run your application on the TV. 120 | -------------------------------------------------------------------------------- /video_decoder_sample/README.md: -------------------------------------------------------------------------------- 1 | # Tizen WASM Video Decoder - Sample Application 2 | 3 | *Table of Contents:* 4 | * [Introduction](#introduction) 5 | * [Building the sample widget with Tizen Studio](#building-the-sample-widget-with-tizen-studio) 6 | * [Prerequisites](#prerequisites) 7 | * [Step-by-step guide](#step-by-step-guide) 8 | * [Required Emscripten flags](#required-emscripten-flags) 9 | 10 | ## Introduction 11 | 12 | This is a sample application showing how to use **[Tizen WASM Video Decoder](https://developer.samsung.com/smarttv/develop/extension-libraries/webassembly/tizen-wasm-player/video-decoder-usage-guide.html)** 13 | to play media on a Samsung Smart TV device using a WebAssembly module. 14 | 15 | This application is an extension to Tizen WASM Player Sample Application. It presents how to extend existing WASM Player application to achieve decoding video frames to GL texture functionality. 16 | 17 | `emss_sdf_sample.h` and `emss_sdf_sample.cc` files have been copied from `wasm_player_sample` application and are used only to manage playback in media player. 18 | Video Decoder logic is located in `video_decoder_sdf_sample.h` and `video_decoder_sdf_sample.cc` files. 19 | 20 | The sample application's features are: 21 | * elementary media stream playback using `HTMLMediaElement` with an 22 | `ElementaryMediaStreamSource` data source and `kVideoTexture` rendering mode, 23 | * [looping video](https://developer.samsung.com/smarttv/develop/extension-libraries/webassembly/tizen-wasm-player/wasm-player-usage-guide.html#loop), 24 | * implementation of [Seeking](https://developer.samsung.com/smarttv/develop/extension-libraries/webassembly/tizen-wasm-player/wasm-player-usage-guide.html#seek) and [Multitasking](https://developer.samsung.com/SmartTV/develop/guides/fundamentals/multitasking.html). 25 | 26 | Packetized data is hardcoded in app to maximize data access simplicity. 27 | 28 | ## Building the sample widget with Tizen Studio 29 | 30 | ### Prerequisites 31 | 32 | Emscripten SDK with Samsung extensions and Tizen Studio are required to build 33 | this sample. Please follow [a guide on Samsung Developers](https://developer.samsung.com/smarttv/develop/extension-libraries/webassembly/getting-started/downloading-and-installing.html) 34 | to learn more about their installation and setup. 35 | 36 | ### Step-by-step guide 37 | 38 | 1. Launch Tizen Studio. 39 | 40 | 2. Create a new WebAssembly-enabled project in Tizen Studio: 41 | * File -> New -> Tizen Project, 42 | * select 'Template' and click 'Next', 43 | * select 'TV' and click 'Next', 44 | * select 'Web Application', check 'WebAssembly (C/C++)' box and click 'Next', 45 | * select 'Empty' application template and click 'Next', 46 | * name the project `VideoDecoderSample` and click 'Next', 47 | * enter paths to the Emscripten configuration file and cache directory 48 | (please refer to [a guide on Tizen Developers](https://developer.samsung.com/smarttv/develop/extension-libraries/webassembly/getting-started/creating-hello-webassembly-tv-application.html) 49 | for details), 50 | * click 'Finish'. 51 | 52 | 3. Add a new WebAssembly module to the project: 53 | * click right mouse button on the project in 'Project Explorer', 54 | * click 'New' -> 'WebAssembly Module' in the context menu, 55 | * select 'Empty module' and click 'Next', 56 | * name the module `VideoDecoderSampleModule` (name is important, as this is the name 57 | used to load the module), 58 | * click 'Finish'. 59 | 60 | 4. Replace default HTML5 and C++ files generated by Tizen Studio with the files 61 | from this sample: 62 | 63 | a. Remove generated HTML5 and C++ files: 64 | * `VideoDecoderSample/index.html` 65 | * `VideoDecoderSample/main.js` 66 | * `VideoDecoderSample/css/style.css` 67 | * `VideoDecoderSampleModule/inc/empty.hpp` 68 | * `VideoDecoderSampleModule/src/empty.cpp` 69 | 70 | b. Copy sample widget's files to the projects in Tizen Studio: 71 | * `elementary_media_stream_source_sample/widget/*` -> `VideoDecoderSample/` 72 | * `elementary_media_stream_source_sample/src/*` -> `VideoDecoderSampleModule/` 73 | 74 | 5. Add necessary compiler and linker flags to the WebAssembly module: 75 | * click right mouse button on the `VideoDecoderSampleModule` project in 'Project 76 | Explorer', 77 | * select 'Properties' from the context menu, 78 | * select 'C/C++ Build' -> 'Settings', 79 | * on 'Tool Settings' tab: 80 | * select 'Emscripten C++ Compiler' -> 'Miscellaneous' and edit 'Other 81 | flags', changing `-std=gnu++11` to `-std=gnu++14`, 82 | * select 'Emscripten C++ Linker' -> 'Miscellaneous': 83 | * append following flags to 'Linker flags': 84 | ```bash 85 | -s ENVIRONMENT_MAY_BE_TIZEN -pthread -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=1 -s USE_SDL=2 86 | ``` 87 | *(flags are explained below, in* Required Emscripten flags *section)* 88 | * remove `-s EXPORT_NAME=VideoDecoderSampleModule -s MODULARIZE=1 ` from 89 | 'Linker flags'. 90 | *Please note:* this step is required, because code loading 91 | modularized and non-modularized WebAssembly modules differ slightly. 92 | This sample is prepared to load modules that doesn't use 93 | `MODULARIZE` option. 94 | * click 'Apply and Close'. 95 | 96 | 6. Build the project: 97 | * click right mouse button on the `VideoDecoderSample` project in 'Project Explorer', 98 | * click 'Build Project' in context menu. 99 | 100 | 7. Create a widget package: 101 | * click right mouse button on the `VideoDecoderSample` project in 'Project Explorer', 102 | * click 'Build Signed Package' in context menu. 103 | 104 | 8. The widget is ready to use! 105 | 106 | ## Required Emscripten flags 107 | 108 | The table below explains Emscripten-specific build flags required to build this 109 | sample: 110 | 111 | | Flag | Description | 112 | |------|-------------| 113 | | `-s ENVIRONMENT_MAY_BE_TIZEN` | Enables usage of Samsung Tizen Emscripten extensions available on Samsung Tizen TVs. This flag is necessary to use Elementary Media Stream Source. | 114 | | `-pthread -s USE_PTHREADS=1` | Enables usage of threads in WebAssembly module. | 115 | | `-s USE_SDL=2` | Flag enabling SDL2 library (libsdl2). | 116 | | `-s PTHREAD_POOL_SIZE=1` | WebAssembly module will be prepared to start indicated number of threads. It's important to set this parameter to a maximum number of threads that an application uses; otherwise starting new threads may fail! See [pthreads](https://emscripten.org/docs/porting/pthreads.html) in Emscripten documentation for more information. | 117 | -------------------------------------------------------------------------------- /video_decoder_sample/src/emss_sdf_sample.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Samsung Electronics Inc. 2 | // Licensed under the MIT license. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | // SOFTWARE. 21 | 22 | // *** Sample Tizen WASM Player Application *** 23 | // 24 | // This file contains sample implementation of a simple WASM module that plays 25 | // media content with Tizen WASM Player using HTMLMediaElement with 26 | // ElementaryMediaStreamSource as a data source. The sample uses hardcoded data 27 | // (see sample_data.h). 28 | 29 | #ifndef WASM_PLAYER_SAMPLE_EMSS_SDF_SAMPLE_H 30 | #define WASM_PLAYER_SAMPLE_EMSS_SDF_SAMPLE_H 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | // This class is responsible for sending elementary media data to Elementary 46 | // Media Stream Source via ElementaryMediaTrack object. 47 | class TrackDataPump : public samsung::wasm::ElementaryMediaTrackListener { 48 | public: 49 | using ElementaryMediaTrack = samsung::wasm::ElementaryMediaTrack; 50 | using Seconds = samsung::wasm::Seconds; 51 | using SessionId = samsung::wasm::SessionId; 52 | 53 | // Controls how many packets should be buffered ahead of a current playback 54 | // position. 55 | static constexpr Seconds kBufferAhead = Seconds{3.}; 56 | 57 | // Worker thread will be notified about advancing playback position every 58 | // kWorkerUpdateThreshold. 59 | static constexpr Seconds kWorkerUpdateThreshold = Seconds{0.5}; 60 | 61 | explicit TrackDataPump(ElementaryMediaTrack video_track); 62 | 63 | ~TrackDataPump() override; 64 | 65 | // Notify pump about stream running time, so that elementary media data can be 66 | // buffered up to (new_time + kBufferAhead). 67 | void UpdateTime(Seconds new_time); 68 | 69 | // samsung::wasm::ElementaryMediaStreamSourceListener interface ////////////// 70 | 71 | // Indicates ElementaryMediaTrack is ready to accept data. 72 | void OnTrackOpen() override; 73 | 74 | // Indicates ElementaryMediaTrack can't accept data. 75 | void OnTrackClosed(ElementaryMediaTrack::CloseReason) override; 76 | 77 | // Track is being seeked. 78 | // 79 | // This happens only when track is closed. When it will open data provider 80 | // should send elementary media data starting from a keyframe closest to the 81 | // new_time. 82 | void OnSeek(Seconds new_time) override; 83 | 84 | // Session id changed: stamp packets with a new session id from now on. 85 | void OnSessionIdChanged(SessionId session_id) override; 86 | 87 | protected: 88 | ElementaryMediaTrack video_track_; 89 | 90 | private: 91 | // Naive implementation of main thread -> worker thread message queue: 92 | class WorkerMessageQueue { 93 | public: 94 | struct Message { 95 | enum class Type { kSetBufferToPts, kSeekTo, kTerminate }; 96 | 97 | Message(Type type, Seconds time, SessionId session_id); 98 | 99 | Type type; 100 | Seconds time; 101 | SessionId session_id; 102 | }; // struct Message 103 | 104 | void Flush(); 105 | Message Pop(); 106 | void PushBufferToPts(Seconds time, SessionId session_id); 107 | void PushSeekTo(Seconds time); 108 | void PushTerminate(); 109 | 110 | private: 111 | void FlushWhileLocked(); 112 | 113 | std::queue message_queue_; 114 | std::condition_variable messages_changed_; 115 | std::mutex messages_mutex_; 116 | }; // class WorkerMessageQueue 117 | 118 | WorkerMessageQueue messages_; 119 | 120 | std::thread pump_worker_; 121 | 122 | Seconds last_reported_running_time_; 123 | SessionId session_id_; 124 | 125 | // A first frame after Seek must always be a keyframe. This method finds a 126 | // closest keyframe preceeding the given time in sample_data. 127 | static size_t GetClosestKeyframeIndex(Seconds time); 128 | 129 | // Sends packets to Source. Executes on a worker thread. 130 | // 131 | // This sample uses a simple, hard-coded media content. However, for a typical 132 | // media application data processing will be more complicated and time 133 | // consuming (e.g. it includes downloading data, demuxing containers, etc). 134 | // Therefore processing of elementary media data on a side thread is advised, 135 | // as it frees main thread (JS thread) and does not hinder application 136 | // responsiveness. 137 | void PumpPackets(); 138 | }; // class TrackDataPump 139 | 140 | class SamplePlayer : public samsung::wasm::ElementaryMediaStreamSourceListener, 141 | public samsung::html::HTMLMediaElementListener { 142 | public: 143 | using ElementaryMediaStreamSource = 144 | samsung::wasm::ElementaryMediaStreamSource; 145 | using ElementaryMediaTrack = samsung::wasm::ElementaryMediaTrack; 146 | using HTMLMediaElement = samsung::html::HTMLMediaElement; 147 | using Seconds = samsung::wasm::Seconds; 148 | 149 | SamplePlayer() = default; 150 | 151 | void SetUp(ElementaryMediaStreamSource::RenderingMode); 152 | 153 | // samsung::wasm::ElementaryMediaStreamSourceListener interface // 154 | 155 | // This event will be fired when ElementaryMediaStreamSource enters kClosed 156 | // state, which happens once it's attached to HTMLMediaElement. Player can be 157 | // configured in kClosed state. 158 | void OnSourceClosed() override; 159 | 160 | void OnPlaybackPositionChanged(Seconds new_time) override; 161 | 162 | // samsung::html::HTMLMediaElementListener interface // 163 | 164 | // This event will be fired as soon as enough data is buffered to start 165 | // playback. 166 | void OnCanPlay() override; 167 | 168 | protected: 169 | virtual std::unique_ptr CreateTrackDataPump( 170 | ElementaryMediaTrack&& video_track); 171 | 172 | std::unique_ptr media_element_; 173 | std::unique_ptr track_data_pump_; 174 | 175 | // Make sure source_ outlives media_element_ when they are associated with 176 | // HTMLMediaElement::SetSrc(). 177 | std::unique_ptr source_; 178 | }; // class SimplePlayer 179 | 180 | #endif // WASM_PLAYER_SAMPLE_EMSS_SDF_SAMPLE_H 181 | -------------------------------------------------------------------------------- /wasm_player_sample/src/emss_sdf_sample.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Samsung Electronics Inc. 2 | // Licensed under the MIT license. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | // SOFTWARE. 21 | 22 | // *** Sample Tizen WASM Player Application *** 23 | // 24 | // This file contains sample implementation of a simple WASM module that plays 25 | // media content with Tizen WASM Player using HTMLMediaElement with 26 | // ElementaryMediaStreamSource as a data source. The sample uses hardcoded data 27 | // (see sample_data.h). 28 | 29 | #ifndef WASM_PLAYER_SAMPLE_EMSS_SDF_SAMPLE_H 30 | #define WASM_PLAYER_SAMPLE_EMSS_SDF_SAMPLE_H 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | // This class is responsible for sending elementary media data to Elementary 46 | // Media Stream Source via ElementaryMediaTrack object. 47 | class TrackDataPump : public samsung::wasm::ElementaryMediaTrackListener { 48 | public: 49 | using ElementaryMediaTrack = samsung::wasm::ElementaryMediaTrack; 50 | using Seconds = samsung::wasm::Seconds; 51 | using SessionId = samsung::wasm::SessionId; 52 | 53 | // Controls how many packets should be buffered ahead of a current playback 54 | // position. 55 | static constexpr Seconds kBufferAhead = Seconds{3.}; 56 | 57 | // Worker thread will be notified about advancing playback position every 58 | // kWorkerUpdateThreshold. 59 | static constexpr Seconds kWorkerUpdateThreshold = Seconds{0.5}; 60 | 61 | explicit TrackDataPump(ElementaryMediaTrack video_track); 62 | 63 | ~TrackDataPump() override; 64 | 65 | // Notify pump about stream running time, so that elementary media data can be 66 | // buffered up to (new_time + kBufferAhead). 67 | void UpdateTime(Seconds new_time); 68 | 69 | // samsung::wasm::ElementaryMediaStreamSourceListener interface ////////////// 70 | 71 | // Indicates ElementaryMediaTrack is ready to accept data. 72 | void OnTrackOpen() override; 73 | 74 | // Indicates ElementaryMediaTrack can't accept data. 75 | void OnTrackClosed(ElementaryMediaTrack::CloseReason) override; 76 | 77 | // Track is being seeked. 78 | // 79 | // This happens only when track is closed. When it will open data provider 80 | // should send elementary media data starting from a keyframe closest to the 81 | // new_time. 82 | void OnSeek(Seconds new_time) override; 83 | 84 | // Session id changed: stamp packets with a new session id from now on. 85 | void OnSessionIdChanged(SessionId session_id) override; 86 | 87 | protected: 88 | ElementaryMediaTrack video_track_; 89 | 90 | private: 91 | // Naive implementation of main thread -> worker thread message queue: 92 | class WorkerMessageQueue { 93 | public: 94 | struct Message { 95 | enum class Type { kSetBufferToPts, kSeekTo, kTerminate }; 96 | 97 | Message(Type type, Seconds time, SessionId session_id); 98 | 99 | Type type; 100 | Seconds time; 101 | SessionId session_id; 102 | }; // struct Message 103 | 104 | void Flush(); 105 | Message Pop(); 106 | void PushBufferToPts(Seconds time, SessionId session_id); 107 | void PushSeekTo(Seconds time); 108 | void PushTerminate(); 109 | 110 | private: 111 | void FlushWhileLocked(); 112 | 113 | std::queue message_queue_; 114 | std::condition_variable messages_changed_; 115 | std::mutex messages_mutex_; 116 | }; // class WorkerMessageQueue 117 | 118 | WorkerMessageQueue messages_; 119 | 120 | std::thread pump_worker_; 121 | 122 | Seconds last_reported_running_time_; 123 | SessionId session_id_; 124 | 125 | // A first frame after Seek must always be a keyframe. This method finds a 126 | // closest keyframe preceeding the given time in sample_data. 127 | static size_t GetClosestKeyframeIndex(Seconds time); 128 | 129 | // Sends packets to Source. Executes on a worker thread. 130 | // 131 | // This sample uses a simple, hard-coded media content. However, for a typical 132 | // media application data processing will be more complicated and time 133 | // consuming (e.g. it includes downloading data, demuxing containers, etc). 134 | // Therefore processing of elementary media data on a side thread is advised, 135 | // as it frees main thread (JS thread) and does not hinder application 136 | // responsiveness. 137 | void PumpPackets(); 138 | }; // class TrackDataPump 139 | 140 | class SamplePlayer : public samsung::wasm::ElementaryMediaStreamSourceListener, 141 | public samsung::html::HTMLMediaElementListener { 142 | public: 143 | using ElementaryMediaStreamSource = 144 | samsung::wasm::ElementaryMediaStreamSource; 145 | using ElementaryMediaTrack = samsung::wasm::ElementaryMediaTrack; 146 | using HTMLMediaElement = samsung::html::HTMLMediaElement; 147 | using Seconds = samsung::wasm::Seconds; 148 | 149 | SamplePlayer() = default; 150 | 151 | void SetUp(ElementaryMediaStreamSource::RenderingMode); 152 | 153 | // samsung::wasm::ElementaryMediaStreamSourceListener interface // 154 | 155 | // This event will be fired when ElementaryMediaStreamSource enters kClosed 156 | // state, which happens once it's attached to HTMLMediaElement. Player can be 157 | // configured in kClosed state. 158 | void OnSourceClosed() override; 159 | 160 | void OnPlaybackPositionChanged(Seconds new_time) override; 161 | 162 | // samsung::html::HTMLMediaElementListener interface // 163 | 164 | // This event will be fired as soon as enough data is buffered to start 165 | // playback. 166 | void OnCanPlay() override; 167 | 168 | protected: 169 | virtual std::unique_ptr CreateTrackDataPump( 170 | ElementaryMediaTrack&& video_track); 171 | 172 | std::unique_ptr media_element_; 173 | std::unique_ptr track_data_pump_; 174 | 175 | // Make sure source_ outlives media_element_ when they are associated with 176 | // HTMLMediaElement::SetSrc(). 177 | std::unique_ptr source_; 178 | }; // class SimplePlayer 179 | 180 | #endif // WASM_PLAYER_SAMPLE_EMSS_SDF_SAMPLE_H 181 | -------------------------------------------------------------------------------- /video_decoder_sample/src/video_decoder_sdf_sample.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Samsung Electronics Inc. 2 | // Licensed under the MIT license. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | // SOFTWARE. 21 | 22 | #include "video_decoder_sdf_sample.h" 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include "sample_data.h" 32 | 33 | #define assertNoGLError() assert(!glGetError()); 34 | 35 | using ElementaryMediaStreamSource = samsung::wasm::ElementaryMediaStreamSource; 36 | using ElementaryMediaStreamSourceListener = 37 | samsung::wasm::ElementaryMediaStreamSourceListener; 38 | using ElementaryMediaTrack = samsung::wasm::ElementaryMediaTrack; 39 | ; 40 | namespace { 41 | 42 | const char kVertexShader[] = 43 | "varying vec2 v_texCoord; \n" 44 | "attribute vec4 a_position; \n" 45 | "attribute vec2 a_texCoord; \n" 46 | "uniform vec2 v_scale; \n" 47 | "void main() \n" 48 | "{ \n" 49 | " v_texCoord = v_scale * a_texCoord; \n" 50 | " gl_Position = a_position; \n" 51 | "}"; 52 | 53 | const char kFragmentShaderExternal[] = 54 | "#extension GL_OES_EGL_image_external : require \n" 55 | "precision mediump float; \n" 56 | "varying vec2 v_texCoord; \n" 57 | "uniform samplerExternalOES s_texture; \n" 58 | "void main() \n" 59 | "{ \n" 60 | " gl_FragColor = texture2D(s_texture, v_texCoord); \n" 61 | "} \n"; 62 | 63 | void CreateShader(GLuint program, GLenum type, const char* source, int size) { 64 | GLuint shader = glCreateShader(type); 65 | glShaderSource(shader, 1, &source, &size); 66 | glCompileShader(shader); 67 | glAttachShader(program, shader); 68 | glDeleteShader(shader); 69 | } 70 | 71 | int CAPIOnDrawTextureCompleted(double /* time */, void* thiz) { 72 | if (thiz) 73 | static_cast(thiz)->OnDrawCompleted(); 74 | 75 | return 0; 76 | } 77 | 78 | } // namespace 79 | 80 | VideoDecoderTrackDataPump::VideoDecoderTrackDataPump( 81 | ElementaryMediaTrack video_track) 82 | : TrackDataPump(std::move(video_track)) { 83 | InitializeGL(); 84 | CreateGLObjects(); 85 | CreateProgram(); 86 | 87 | video_track_.RegisterCurrentGraphicsContext(); 88 | } 89 | 90 | void VideoDecoderTrackDataPump::OnDrawCompleted() { 91 | video_track_.RecycleTexture(texture_); 92 | RequestNewVideoTexture(); 93 | } 94 | 95 | void VideoDecoderTrackDataPump::RequestNewVideoTexture() { 96 | video_track_.FillTextureWithNextFrame( 97 | texture_, [this](samsung::wasm::OperationResult result) { 98 | if (result != samsung::wasm::OperationResult::kSuccess) { 99 | std::cout << "Filling texture with next frame failed" << std::endl; 100 | return; 101 | } 102 | 103 | Draw(); 104 | }); 105 | } 106 | 107 | void VideoDecoderTrackDataPump::CreateGLObjects() { 108 | // Assign vertex positions and texture coordinates to buffers for use in 109 | // shader program. 110 | static const float kVertices[] = { 111 | -1, -1, -1, 1, 1, -1, 1, 1, // Position coordinates. 112 | 0, 1, 0, 0, 1, 1, 1, 0, // Texture coordinates. 113 | }; 114 | 115 | GLuint buffer; 116 | glGenBuffers(1, &buffer); 117 | glBindBuffer(GL_ARRAY_BUFFER, buffer); 118 | glBufferData(GL_ARRAY_BUFFER, sizeof(kVertices), kVertices, GL_STATIC_DRAW); 119 | assertNoGLError(); 120 | } 121 | 122 | void VideoDecoderTrackDataPump::CreateProgram() { 123 | // Create shader program. 124 | program_ = glCreateProgram(); 125 | CreateShader(program_, GL_VERTEX_SHADER, kVertexShader, 126 | strlen(kVertexShader)); 127 | CreateShader(program_, GL_FRAGMENT_SHADER, kFragmentShaderExternal, 128 | strlen(kFragmentShaderExternal)); 129 | glLinkProgram(program_); 130 | glUseProgram(program_); 131 | glUniform1i(glGetUniformLocation(program_, "s_texture"), 0); 132 | assertNoGLError(); 133 | 134 | texcoord_scale_location_ = glGetUniformLocation(program_, "v_scale"); 135 | 136 | assertNoGLError(); 137 | 138 | GLint pos_location = glGetAttribLocation(program_, "a_position"); 139 | GLint tc_location = glGetAttribLocation(program_, "a_texCoord"); 140 | 141 | glEnableVertexAttribArray(pos_location); 142 | glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, 0); 143 | glEnableVertexAttribArray(tc_location); 144 | glVertexAttribPointer( 145 | tc_location, 2, GL_FLOAT, GL_FALSE, 0, 146 | static_cast(0) + 8); // Skip position coordinates. 147 | 148 | glUseProgram(0); 149 | } 150 | 151 | void VideoDecoderTrackDataPump::Draw() { 152 | glUseProgram(program_); 153 | glUniform2f(texcoord_scale_location_, 1.0, 1.0); 154 | 155 | glActiveTexture(GL_TEXTURE0); 156 | glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_); 157 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 158 | assertNoGLError(); 159 | 160 | emscripten_request_animation_frame(&CAPIOnDrawTextureCompleted, this); 161 | } 162 | 163 | void VideoDecoderTrackDataPump::InitializeSDL() { 164 | SDL_Init(SDL_INIT_VIDEO); 165 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); 166 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); 167 | SDL_GL_SetSwapInterval(1); 168 | SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); 169 | SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); 170 | SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); 171 | SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4); 172 | } 173 | 174 | void VideoDecoderTrackDataPump::InitializeGL() { 175 | InitializeSDL(); 176 | int width; 177 | int height; 178 | emscripten_get_canvas_element_size("#canvas", &width, &height); 179 | window_ = SDL_CreateWindow("VideoTexture", SDL_WINDOWPOS_CENTERED, 180 | SDL_WINDOWPOS_CENTERED, width, height, 181 | SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN); 182 | gl_context_ = SDL_GL_CreateContext(window_); 183 | SDL_GL_MakeCurrent(window_, gl_context_); 184 | glGenTextures(1, &texture_); 185 | glViewport(0, 0, width, height); 186 | glClearColor(1, 0, 0, 0); 187 | glClear(GL_COLOR_BUFFER_BIT); 188 | } 189 | 190 | void VideoDecoderSamplePlayer::OnCanPlay() { 191 | if (!media_element_->IsPaused()) 192 | return; 193 | 194 | media_element_->Play([this](samsung::wasm::OperationResult result) { 195 | if (result != samsung::wasm::OperationResult::kSuccess) { 196 | std::cout << "Cannot play." << std::endl; 197 | return; 198 | } 199 | 200 | // This cast is safe, because function CreateTrackDataPump has been 201 | // overriden in this class, so track_data_pump_ holds 202 | // VideoDecoderTrackDataPump object. 203 | auto* video_decoder_track_data_pump = 204 | static_cast(track_data_pump_.get()); 205 | video_decoder_track_data_pump->RequestNewVideoTexture(); 206 | }); 207 | } 208 | 209 | std::unique_ptr VideoDecoderSamplePlayer::CreateTrackDataPump( 210 | ElementaryMediaTrack&& video_track) { 211 | return std::make_unique(std::move(video_track)); 212 | } 213 | -------------------------------------------------------------------------------- /video_decoder_sample/src/emss_sdf_sample.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Samsung Electronics Inc. 2 | // Licensed under the MIT license. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | // SOFTWARE. 21 | 22 | #include "emss_sdf_sample.h" 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include "sample_data.h" 29 | 30 | using ElementaryMediaStreamSource = samsung::wasm::ElementaryMediaStreamSource; 31 | using ElementaryMediaStreamSourceListener = 32 | samsung::wasm::ElementaryMediaStreamSourceListener; 33 | using ElementaryMediaTrack = samsung::wasm::ElementaryMediaTrack; 34 | using ElementaryMediaTrackListener = 35 | samsung::wasm::ElementaryMediaTrackListener; 36 | using HTMLMediaElement = samsung::html::HTMLMediaElement; 37 | using HTMLMediaElementListener = samsung::html::HTMLMediaElementListener; 38 | using Seconds = samsung::wasm::Seconds; 39 | using SessionId = samsung::wasm::SessionId; 40 | 41 | static constexpr char kVideoTagId[] = "video-element"; 42 | 43 | TrackDataPump::TrackDataPump(ElementaryMediaTrack video_track) 44 | : video_track_(std::move(video_track)), 45 | pump_worker_([this]() { this->PumpPackets(); }), 46 | last_reported_running_time_(0), 47 | session_id_(video_track_.GetSessionId().value) { 48 | video_track_.SetListener(this); 49 | } 50 | 51 | TrackDataPump::~TrackDataPump() { 52 | messages_.PushTerminate(); 53 | pump_worker_.detach(); 54 | } 55 | 56 | void TrackDataPump::UpdateTime(Seconds new_time) { 57 | if (last_reported_running_time_ + kWorkerUpdateThreshold > new_time) { 58 | // Extensive locking of main (JS) thread should be avoided 59 | // (and in this case - it is also not needed), therefore update 60 | // frequency is throttled to kWorkerUpdateThreshold. 61 | return; 62 | } 63 | last_reported_running_time_ = new_time; 64 | messages_.PushBufferToPts(new_time + kBufferAhead, session_id_); 65 | } 66 | 67 | void TrackDataPump::OnTrackOpen() { 68 | // Trigger buffering immediately. 69 | messages_.PushBufferToPts(last_reported_running_time_ + kBufferAhead, 70 | session_id_); 71 | } 72 | 73 | void TrackDataPump::OnTrackClosed(ElementaryMediaTrack::CloseReason) { 74 | messages_.Flush(); 75 | } 76 | 77 | void TrackDataPump::OnSeek(Seconds new_time) { 78 | last_reported_running_time_ = new_time; 79 | messages_.PushSeekTo(new_time); 80 | } 81 | 82 | void TrackDataPump::OnSessionIdChanged(SessionId session_id) { 83 | session_id_ = session_id; 84 | } 85 | 86 | TrackDataPump::WorkerMessageQueue::Message::Message(Type type, 87 | Seconds time, 88 | SessionId session_id) 89 | : type(type), time(time), session_id(session_id) {} 90 | 91 | void TrackDataPump::WorkerMessageQueue::Flush() { 92 | std::unique_lock lock{messages_mutex_}; 93 | FlushWhileLocked(); 94 | } 95 | 96 | TrackDataPump::WorkerMessageQueue::Message 97 | TrackDataPump::WorkerMessageQueue::Pop() { 98 | std::unique_lock lock{messages_mutex_}; 99 | while (message_queue_.empty()) { 100 | messages_changed_.wait(lock); 101 | } 102 | auto result = message_queue_.front(); 103 | message_queue_.pop(); 104 | return result; 105 | } 106 | 107 | void TrackDataPump::WorkerMessageQueue::PushBufferToPts(Seconds time, 108 | SessionId session_id) { 109 | { 110 | std::lock_guard lock{messages_mutex_}; 111 | message_queue_.emplace(WorkerMessageQueue::Message::Type::kSetBufferToPts, 112 | time, session_id); 113 | } 114 | messages_changed_.notify_one(); 115 | } 116 | 117 | void TrackDataPump::WorkerMessageQueue::PushSeekTo(Seconds time) { 118 | { 119 | // Seek invalidates any actions queued previously. 120 | FlushWhileLocked(); 121 | std::lock_guard lock{messages_mutex_}; 122 | message_queue_.emplace(WorkerMessageQueue::Message::Type::kSeekTo, time, 123 | 0 /* ignored for kSeekTo */); 124 | } 125 | messages_changed_.notify_one(); 126 | } 127 | 128 | void TrackDataPump::WorkerMessageQueue::PushTerminate() { 129 | { 130 | std::lock_guard lock{messages_mutex_}; 131 | FlushWhileLocked(); 132 | message_queue_.emplace(WorkerMessageQueue::Message::Type::kTerminate, 133 | Seconds{0} /* ignored for kTerminate */, 134 | 0 /* ignored for kTerminate */); 135 | } 136 | messages_changed_.notify_one(); 137 | } 138 | 139 | void TrackDataPump::WorkerMessageQueue::FlushWhileLocked() { 140 | std::queue tmp; 141 | message_queue_.swap(tmp); 142 | } 143 | 144 | // static 145 | size_t TrackDataPump::GetClosestKeyframeIndex(Seconds time) { 146 | auto keyframe = std::find_if( 147 | sample_data::kVideoPackets.crbegin(), sample_data::kVideoPackets.crend(), 148 | [time](const auto& packet) { 149 | return (packet.is_key_frame && packet.pts < time); 150 | }); 151 | if (keyframe == sample_data::kVideoPackets.crend()) 152 | return 0; 153 | return (&(*keyframe) - sample_data::kVideoPackets.data()); 154 | } 155 | 156 | void TrackDataPump::PumpPackets() { 157 | using Message = WorkerMessageQueue::Message; 158 | auto ended = false; 159 | auto packet_idx = 0u; 160 | auto session_id = 0u; 161 | while (true) { 162 | auto message = messages_.Pop(); 163 | switch (message.type) { 164 | case Message::Type::kSetBufferToPts: 165 | session_id = message.session_id; 166 | while (packet_idx < sample_data::kVideoPackets.size() && 167 | sample_data::kVideoPackets[packet_idx].pts < message.time) { 168 | auto packet = sample_data::kVideoPackets[packet_idx]; 169 | packet.session_id = session_id; 170 | video_track_.AppendPacket(packet); 171 | ++packet_idx; 172 | } 173 | if (!ended && packet_idx == sample_data::kVideoPackets.size()) { 174 | // Make sure to mark track as ended once all packets were sent. 175 | // Since HTML video tag's 'loop' property is set, Elementary Media 176 | // Stream Source will automatically seek to 0s once playback reaches 177 | // end. 178 | ended = true; 179 | video_track_.AppendEndOfTrack(session_id); 180 | } 181 | break; 182 | case Message::Type::kSeekTo: 183 | ended = false; 184 | packet_idx = GetClosestKeyframeIndex(message.time); 185 | break; 186 | case Message::Type::kTerminate: 187 | return; 188 | } 189 | } 190 | } 191 | 192 | void SamplePlayer::SetUp( 193 | ElementaryMediaStreamSource::RenderingMode rendering_mode) { 194 | media_element_ = std::make_unique(kVideoTagId); 195 | media_element_->SetListener(this); 196 | 197 | source_ = std::make_unique( 198 | ElementaryMediaStreamSource::LatencyMode::kNormal, rendering_mode); 199 | source_->SetListener(this); 200 | 201 | // When source_ is successfully attached to media_element_, it will change 202 | // state from kDetached to kClosed. This results in OnSourceClosed() firing, 203 | // where setting player up can continue. 204 | media_element_->SetSrc(source_.get()); 205 | } 206 | 207 | void SamplePlayer::OnSourceClosed() { 208 | // First, Source needs to be configured: 209 | source_->SetDuration(sample_data::kStreamDuration); 210 | auto add_track_result = source_->AddTrack(sample_data::kVideoTrackConfig); 211 | if (!add_track_result) { 212 | std::cout << "Cannot add a video track!" << std::endl; 213 | return; 214 | } 215 | auto video_track = std::move(add_track_result.value); 216 | track_data_pump_ = CreateTrackDataPump(std::move(video_track)); 217 | 218 | // Then Source can be requested to enter kOpen state (where it can accept 219 | // elementary media data). 220 | source_->Open([](auto result) { 221 | if (result != samsung::wasm::OperationResult::kSuccess) { 222 | std::cout << "Cannot open ElementaryMediaStreamSource." << std::endl; 223 | } 224 | // Source entered kOpen state after Open() request. 225 | // 226 | // App can send elementary media data to ElementaryMediaTrack now, so 227 | // packet sending mechanism should be started. Since entering kOpen state 228 | // can be triggered by reasons other than calling Open(), code that 229 | // controls sending packets should be placed either in 230 | // ElementaryMediaStreamSourceListener::OnSourceOpen() or in 231 | // ElementaryMediaTrackListener::OnTrackOpen(). 232 | // 233 | // The latter option is preferred and is used in TrackDataPump. 234 | }); 235 | } 236 | 237 | void SamplePlayer::OnPlaybackPositionChanged(Seconds new_time) { 238 | if (track_data_pump_) { 239 | // Broadcast new time to a component managing data buffering... 240 | track_data_pump_->UpdateTime(new_time); 241 | } 242 | } 243 | 244 | void SamplePlayer::OnCanPlay() { 245 | if (!media_element_->IsPaused()) 246 | return; 247 | 248 | media_element_->Play([](samsung::wasm::OperationResult result) { 249 | if (result != samsung::wasm::OperationResult::kSuccess) { 250 | std::cout << "Cannot play." << std::endl; 251 | } 252 | }); 253 | } 254 | 255 | std::unique_ptr SamplePlayer::CreateTrackDataPump( 256 | ElementaryMediaTrack&& video_track) { 257 | return std::make_unique(std::move(video_track)); 258 | } 259 | -------------------------------------------------------------------------------- /wasm_player_sample/src/emss_sdf_sample.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Samsung Electronics Inc. 2 | // Licensed under the MIT license. 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | // SOFTWARE. 21 | 22 | #include "emss_sdf_sample.h" 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include "sample_data.h" 29 | 30 | using ElementaryMediaStreamSource = samsung::wasm::ElementaryMediaStreamSource; 31 | using ElementaryMediaStreamSourceListener = 32 | samsung::wasm::ElementaryMediaStreamSourceListener; 33 | using ElementaryMediaTrack = samsung::wasm::ElementaryMediaTrack; 34 | using ElementaryMediaTrackListener = 35 | samsung::wasm::ElementaryMediaTrackListener; 36 | using HTMLMediaElement = samsung::html::HTMLMediaElement; 37 | using HTMLMediaElementListener = samsung::html::HTMLMediaElementListener; 38 | using Seconds = samsung::wasm::Seconds; 39 | using SessionId = samsung::wasm::SessionId; 40 | 41 | static constexpr char kVideoTagId[] = "video-element"; 42 | 43 | TrackDataPump::TrackDataPump(ElementaryMediaTrack video_track) 44 | : video_track_(std::move(video_track)), 45 | pump_worker_([this]() { this->PumpPackets(); }), 46 | last_reported_running_time_(0), 47 | session_id_(video_track_.GetSessionId().value) { 48 | video_track_.SetListener(this); 49 | } 50 | 51 | TrackDataPump::~TrackDataPump() { 52 | messages_.PushTerminate(); 53 | pump_worker_.detach(); 54 | } 55 | 56 | void TrackDataPump::UpdateTime(Seconds new_time) { 57 | if (last_reported_running_time_ + kWorkerUpdateThreshold > new_time) { 58 | // Extensive locking of main (JS) thread should be avoided 59 | // (and in this case - it is also not needed), therefore update 60 | // frequency is throttled to kWorkerUpdateThreshold. 61 | return; 62 | } 63 | last_reported_running_time_ = new_time; 64 | messages_.PushBufferToPts(new_time + kBufferAhead, session_id_); 65 | } 66 | 67 | void TrackDataPump::OnTrackOpen() { 68 | // Trigger buffering immediately. 69 | messages_.PushBufferToPts(last_reported_running_time_ + kBufferAhead, 70 | session_id_); 71 | } 72 | 73 | void TrackDataPump::OnTrackClosed(ElementaryMediaTrack::CloseReason) { 74 | messages_.Flush(); 75 | } 76 | 77 | void TrackDataPump::OnSeek(Seconds new_time) { 78 | last_reported_running_time_ = new_time; 79 | messages_.PushSeekTo(new_time); 80 | } 81 | 82 | void TrackDataPump::OnSessionIdChanged(SessionId session_id) { 83 | session_id_ = session_id; 84 | } 85 | 86 | TrackDataPump::WorkerMessageQueue::Message::Message(Type type, 87 | Seconds time, 88 | SessionId session_id) 89 | : type(type), time(time), session_id(session_id) {} 90 | 91 | void TrackDataPump::WorkerMessageQueue::Flush() { 92 | std::unique_lock lock{messages_mutex_}; 93 | FlushWhileLocked(); 94 | } 95 | 96 | TrackDataPump::WorkerMessageQueue::Message 97 | TrackDataPump::WorkerMessageQueue::Pop() { 98 | std::unique_lock lock{messages_mutex_}; 99 | while (message_queue_.empty()) { 100 | messages_changed_.wait(lock); 101 | } 102 | auto result = message_queue_.front(); 103 | message_queue_.pop(); 104 | return result; 105 | } 106 | 107 | void TrackDataPump::WorkerMessageQueue::PushBufferToPts(Seconds time, 108 | SessionId session_id) { 109 | { 110 | std::lock_guard lock{messages_mutex_}; 111 | message_queue_.emplace(WorkerMessageQueue::Message::Type::kSetBufferToPts, 112 | time, session_id); 113 | } 114 | messages_changed_.notify_one(); 115 | } 116 | 117 | void TrackDataPump::WorkerMessageQueue::PushSeekTo(Seconds time) { 118 | { 119 | // Seek invalidates any actions queued previously. 120 | FlushWhileLocked(); 121 | std::lock_guard lock{messages_mutex_}; 122 | message_queue_.emplace(WorkerMessageQueue::Message::Type::kSeekTo, time, 123 | 0 /* ignored for kSeekTo */); 124 | } 125 | messages_changed_.notify_one(); 126 | } 127 | 128 | void TrackDataPump::WorkerMessageQueue::PushTerminate() { 129 | { 130 | std::lock_guard lock{messages_mutex_}; 131 | FlushWhileLocked(); 132 | message_queue_.emplace(WorkerMessageQueue::Message::Type::kTerminate, 133 | Seconds{0} /* ignored for kTerminate */, 134 | 0 /* ignored for kTerminate */); 135 | } 136 | messages_changed_.notify_one(); 137 | } 138 | 139 | void TrackDataPump::WorkerMessageQueue::FlushWhileLocked() { 140 | std::queue tmp; 141 | message_queue_.swap(tmp); 142 | } 143 | 144 | // static 145 | size_t TrackDataPump::GetClosestKeyframeIndex(Seconds time) { 146 | auto keyframe = std::find_if( 147 | sample_data::kVideoPackets.crbegin(), sample_data::kVideoPackets.crend(), 148 | [time](const auto& packet) { 149 | return (packet.is_key_frame && packet.pts < time); 150 | }); 151 | if (keyframe == sample_data::kVideoPackets.crend()) 152 | return 0; 153 | return (&(*keyframe) - sample_data::kVideoPackets.data()); 154 | } 155 | 156 | void TrackDataPump::PumpPackets() { 157 | using Message = WorkerMessageQueue::Message; 158 | auto ended = false; 159 | auto packet_idx = 0u; 160 | auto session_id = 0u; 161 | while (true) { 162 | auto message = messages_.Pop(); 163 | switch (message.type) { 164 | case Message::Type::kSetBufferToPts: 165 | session_id = message.session_id; 166 | while (packet_idx < sample_data::kVideoPackets.size() && 167 | sample_data::kVideoPackets[packet_idx].pts < message.time) { 168 | auto packet = sample_data::kVideoPackets[packet_idx]; 169 | packet.session_id = session_id; 170 | video_track_.AppendPacket(packet); 171 | ++packet_idx; 172 | } 173 | if (!ended && packet_idx == sample_data::kVideoPackets.size()) { 174 | // Make sure to mark track as ended once all packets were sent. 175 | // Since HTML video tag's 'loop' property is set, Elementary Media 176 | // Stream Source will automatically seek to 0s once playback reaches 177 | // end. 178 | ended = true; 179 | video_track_.AppendEndOfTrack(session_id); 180 | } 181 | break; 182 | case Message::Type::kSeekTo: 183 | ended = false; 184 | packet_idx = GetClosestKeyframeIndex(message.time); 185 | break; 186 | case Message::Type::kTerminate: 187 | return; 188 | } 189 | } 190 | } 191 | 192 | void SamplePlayer::SetUp( 193 | ElementaryMediaStreamSource::RenderingMode rendering_mode) { 194 | media_element_ = std::make_unique(kVideoTagId); 195 | media_element_->SetListener(this); 196 | 197 | source_ = std::make_unique( 198 | ElementaryMediaStreamSource::LatencyMode::kNormal, rendering_mode); 199 | source_->SetListener(this); 200 | 201 | // When source_ is successfully attached to media_element_, it will change 202 | // state from kDetached to kClosed. This results in OnSourceClosed() firing, 203 | // where setting player up can continue. 204 | media_element_->SetSrc(source_.get()); 205 | } 206 | 207 | void SamplePlayer::OnSourceClosed() { 208 | // First, Source needs to be configured: 209 | source_->SetDuration(sample_data::kStreamDuration); 210 | auto add_track_result = source_->AddTrack(sample_data::kVideoTrackConfig); 211 | if (!add_track_result) { 212 | std::cout << "Cannot add a video track!" << std::endl; 213 | return; 214 | } 215 | auto video_track = std::move(add_track_result.value); 216 | track_data_pump_ = CreateTrackDataPump(std::move(video_track)); 217 | 218 | // Then Source can be requested to enter kOpen state (where it can accept 219 | // elementary media data). 220 | source_->Open([](auto result) { 221 | if (result != samsung::wasm::OperationResult::kSuccess) { 222 | std::cout << "Cannot open ElementaryMediaStreamSource." << std::endl; 223 | } 224 | // Source entered kOpen state after Open() request. 225 | // 226 | // App can send elementary media data to ElementaryMediaTrack now, so 227 | // packet sending mechanism should be started. Since entering kOpen state 228 | // can be triggered by reasons other than calling Open(), code that 229 | // controls sending packets should be placed either in 230 | // ElementaryMediaStreamSourceListener::OnSourceOpen() or in 231 | // ElementaryMediaTrackListener::OnTrackOpen(). 232 | // 233 | // The latter option is preferred and is used in TrackDataPump. 234 | }); 235 | } 236 | 237 | void SamplePlayer::OnPlaybackPositionChanged(Seconds new_time) { 238 | if (track_data_pump_) { 239 | // Broadcast new time to a component managing data buffering... 240 | track_data_pump_->UpdateTime(new_time); 241 | } 242 | } 243 | 244 | void SamplePlayer::OnCanPlay() { 245 | if (!media_element_->IsPaused()) 246 | return; 247 | 248 | media_element_->Play([](samsung::wasm::OperationResult result) { 249 | if (result != samsung::wasm::OperationResult::kSuccess) { 250 | std::cout << "Cannot play." << std::endl; 251 | } 252 | }); 253 | } 254 | 255 | std::unique_ptr SamplePlayer::CreateTrackDataPump( 256 | ElementaryMediaTrack&& video_track) { 257 | return std::make_unique(std::move(video_track)); 258 | } 259 | --------------------------------------------------------------------------------