1/*
2 * Copyright (c) 2022-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15#ifdef OHOS_LITE
16#define HST_LOG_TAG "LiteStreamPlayer"
17
18#define LOG_TAG "main"
19
20#include <chrono>
21#include <cstring>
22#include <cstdio>
23#include <fstream>
24#include <iostream>
25#include <memory>
26#include <sstream>
27#include <string>
28#include <thread>
29#include <vector>
30
31#include "scene/lite/hiplayer.h"
32#include "securec.h"
33#include "foundation/log.h"
34#include "foundation/multimedia/media_utils_lite/interfaces/kits/data_stream.h"
35#include "foundation/osal/utils/util.h"
36#include "foundation/osal/thread/task.h"
37
38using namespace OHOS::Media;
39
40#define INPUT_BUFFER_SIZE           10 * 1024
41#define INPUT_BUFFER_ITEM           3
42
43static uint32_t readPos = 0;
44std::vector<uint32_t> testData;
45uint32_t testDataSize = 0;
46std::shared_ptr<DataStream> stream = nullptr;
47std::shared_ptr<OSAL::Task> task = nullptr;
48
49enum SourceFlag {
50    SOURCE_EOS,
51};
52
53uint8_t *GetDataFromSource(int8_t *flag, uint32_t *getDataSize)
54{
55    uint32_t inputSize = INPUT_BUFFER_SIZE;
56    MEDIA_LOG_I("testDataSize:" PUBLIC_LOG_U32 " ,readPos:" PUBLIC_LOG_U32, testDataSize, readPos);
57    uint8_t *outDataPtr = nullptr;
58    if (readPos == testDataSize) {
59        *flag = SOURCE_EOS;
60        *getDataSize = 0;
61        return outDataPtr;
62    }
63    outDataPtr = reinterpret_cast<uint8_t*>(malloc(inputSize));
64    auto ret = memset_s(outDataPtr, INPUT_BUFFER_SIZE, 0, inputSize);
65    FALSE_RETURN(ret == 0);
66    if (readPos + INPUT_BUFFER_SIZE > testDataSize) {
67        inputSize = testDataSize - readPos;
68    }
69    (void)memcpy_s(outDataPtr, INPUT_BUFFER_SIZE, &testData[0] + readPos / sizeof(uint32_t), inputSize);
70    readPos += inputSize;
71    MEDIA_LOG_I("readPo:" PUBLIC_LOG_U32, readPos);
72    *getDataSize = inputSize;
73    return outDataPtr;
74}
75
76bool g_playFinished = false;
77
78void DataProcessThread()
79{
80    MEDIA_LOG_I("DataProcessThread in");
81    while (!g_playFinished) {
82        int8_t sourceFlag = -1;
83        uint32_t realGetSize = 0;
84        uint8_t *sourceData = GetDataFromSource(&sourceFlag, &realGetSize);
85        std::shared_ptr<DataBuffer> buffer;
86        (void) stream->GetEmptyBuffer(buffer);
87        if (buffer == nullptr) {
88            MEDIA_LOG_E("buffer null error.");
89            if (sourceData != nullptr) {
90                free(sourceData);
91            }
92            return;
93        } else {
94            MEDIA_LOG_I("realGetSize:" PUBLIC_LOG_U32, realGetSize);
95            if (sourceData != nullptr) { // get data
96                (void) memcpy_s(buffer->GetAddress(), buffer->GetCapacity(), sourceData, realGetSize);
97                buffer->SetSize(realGetSize);
98                free(sourceData);
99            } else { // not get data, must be eos
100                buffer->SetSize(0);
101                FALSE_LOG(sourceFlag == SOURCE_EOS);
102                MEDIA_LOG_I("SourceEos");
103                buffer->SetEos(true);
104                stream->QueueDataBuffer(buffer);
105                break;
106            }
107            stream->QueueDataBuffer(buffer);
108        }
109    }
110    task->StopAsync();
111}
112
113class PlayerCallbackImpl : public PlayerCallback {
114    void OnPlaybackComplete() override
115    {
116        g_playFinished = true;
117        MEDIA_LOG_I("OnPlaybackComplete called, g_playFinished is true now.");
118    }
119    void OnError(int32_t errorType, int32_t errorCode) override
120    {
121    }
122    void OnInfo(int type, int extra) override
123    {
124    }
125    void OnVideoSizeChanged(int width, int height) override
126    {
127    }
128    void OnRewindToComplete() override
129    {
130    }
131};
132
133int ReadDataFromFile(std::string dataPath)
134{
135    std::string dataFullPath;
136    if (OSAL::ConvertFullPath(dataPath, dataFullPath) && !dataFullPath.empty()) {
137        dataPath = dataFullPath;
138    }
139    std::fstream fs(dataPath);
140    if (!fs.is_open()) {
141        std::cout << "failed to open " << dataPath << '\n';
142        return 0;
143    }
144    std::stringstream ss;
145    while (!fs.eof()) {
146        std::string s;
147        fs >> s;
148        ss << s;
149    }
150    std::string data = ss.str();
151    const char* split = ",";
152    char* s_input = data.c_str();
153    char* p = strtok(s_input, split);
154    while (p != nullptr) {
155        uint32_t dataValue;
156        auto ret = sscanf_s(p, "%x", &dataValue);
157        FALSE_LOG_MSG_W(ret == 0, "sscanf_s failed.");
158        testData.push_back(dataValue);
159        p=strtok(nullptr, split);
160    }
161    return testData.size() * 4; // 4
162}
163
164int StartLiteStreamPlayer(const std::string& dataPath)
165{
166    MEDIA_LOG_I("Use media_lite interface player.");
167    g_playFinished = false;
168    auto player = OHOS::Media::CreateHiPlayer();
169    player->Init();
170    auto callback = std::make_shared<PlayerCallbackImpl>();
171    player->SetPlayerCallback(callback);
172    stream = CreateDataStream(INPUT_BUFFER_SIZE, INPUT_BUFFER_ITEM);
173    if (stream == nullptr) {
174        MEDIA_LOG_E("Create data stream fail.");
175        return -1;
176    }
177    OHOS::Media::Source source(stream);
178    player->SetSource(source);
179    player->SetLoop(false);
180    testDataSize = ReadDataFromFile(dataPath);
181    if (!testDataSize) {
182        MEDIA_LOG_E("Get data size fail.");
183        return -1;
184    }
185    MEDIA_LOG_I("testDataSize:" PUBLIC_LOG_U32, testDataSize);
186    task = std::make_shared<OSAL::Task>("DataProcessThread");
187    task->RegisterHandler(DataProcessThread);
188    task->Start();
189    player->Prepare();
190    player->Play();
191    while (!g_playFinished) {
192        std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 100
193        MEDIA_LOG_I("stream player thread running...");
194    }
195    readPos = 0;
196    stream = nullptr;
197    return 0;
198}
199#endif