(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 |
--------------------------------------------------------------------------------