1/*
2 * Copyright (C) 2023 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#include <vector>
16#include <unistd.h>
17#include <fcntl.h>
18#include "i_avcodec_service.h"
19#include "avcodec_errors.h"
20#include "avcodec_log.h"
21#include "avcodec_trace.h"
22#include "avsource_impl.h"
23#include "common/media_source.h"
24#include "common/status.h"
25
26namespace {
27    constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_DEMUXER, "AVSourceImpl"};
28}
29
30namespace OHOS {
31namespace MediaAVCodec {
32using namespace Media;
33using namespace Media::Plugins;
34std::shared_ptr<AVSource> AVSourceFactory::CreateWithURI(const std::string &uri)
35{
36    AVCODEC_SYNC_TRACE;
37
38    AVCODEC_LOGD("Create source with uri %{private}s", uri.c_str());
39
40    std::shared_ptr<AVSourceImpl> sourceImpl = std::make_shared<AVSourceImpl>();
41    CHECK_AND_RETURN_RET_LOG(sourceImpl != nullptr, nullptr, "New avsource failed");
42
43    int32_t ret = sourceImpl->InitWithURI(uri);
44
45    CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "Init avsource failed");
46
47    return sourceImpl;
48}
49
50std::shared_ptr<AVSource> AVSourceFactory::CreateWithFD(int32_t fd, int64_t offset, int64_t size)
51{
52    AVCODEC_SYNC_TRACE;
53
54    AVCODEC_LOGD("Create source with fd %{private}d, offset=%{public}" PRId64 ", size=%{public}" PRId64,
55        fd, offset, size);
56
57    std::shared_ptr<AVSourceImpl> sourceImpl = std::make_shared<AVSourceImpl>();
58    CHECK_AND_RETURN_RET_LOG(sourceImpl != nullptr, nullptr, "New avsource failed");
59
60    int32_t ret = sourceImpl->InitWithFD(fd, offset, size);
61
62    CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "Init avsource failed");
63
64    return sourceImpl;
65}
66
67std::shared_ptr<AVSource> AVSourceFactory::CreateWithDataSource(
68    const std::shared_ptr<Media::IMediaDataSource> &dataSource)
69{
70    AVCODEC_SYNC_TRACE;
71
72    std::shared_ptr<AVSourceImpl> sourceImpl = std::make_shared<AVSourceImpl>();
73    CHECK_AND_RETURN_RET_LOG(sourceImpl != nullptr, nullptr, "New avsource failed");
74
75    int32_t ret = sourceImpl->InitWithDataSource(dataSource);
76
77    CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "Init avsource failed");
78
79    return sourceImpl;
80}
81
82int32_t AVSourceImpl::InitWithURI(const std::string &uri)
83{
84    AVCODEC_SYNC_TRACE;
85
86    CHECK_AND_RETURN_RET_LOG(mediaDemuxer == nullptr, AVCS_ERR_INVALID_OPERATION, "Has been used by demuxer");
87    mediaDemuxer = std::make_shared<MediaDemuxer>();
88    mediaDemuxer->SetPlayerId("AVSource_URI");
89    CHECK_AND_RETURN_RET_LOG(mediaDemuxer != nullptr, AVCS_ERR_INVALID_OPERATION, "Create mediaDemuxer failed");
90
91    std::shared_ptr<MediaSource> mediaSource = std::make_shared<MediaSource>(uri);
92    Status ret = mediaDemuxer->SetDataSource(mediaSource);
93    CHECK_AND_RETURN_RET_LOG(ret == Status::OK, StatusToAVCodecServiceErrCode(ret), "Set data source failed");
94
95    sourceUri = uri;
96    return AVCS_ERR_OK;
97}
98
99int32_t AVSourceImpl::InitWithFD(int32_t fd, int64_t offset, int64_t size)
100{
101    AVCODEC_SYNC_TRACE;
102
103    CHECK_AND_RETURN_RET_LOG(mediaDemuxer == nullptr, AVCS_ERR_INVALID_OPERATION, "Has been used by demuxer");
104    CHECK_AND_RETURN_RET_LOG(fd >= 0, AVCS_ERR_INVALID_VAL, "Input fd is negative");
105    if (fd <= STDERR_FILENO) {
106        AVCODEC_LOGW("Using special fd: %{public}d, isatty: %{public}d", fd, isatty(fd));
107    }
108    CHECK_AND_RETURN_RET_LOG(offset >= 0, AVCS_ERR_INVALID_VAL, "Input offset is negative");
109    CHECK_AND_RETURN_RET_LOG(size > 0, AVCS_ERR_INVALID_VAL, "Input size must be greater than zero");
110    int32_t flag = fcntl(fd, F_GETFL, 0);
111    CHECK_AND_RETURN_RET_LOG(flag >= 0, AVCS_ERR_INVALID_VAL, "Get fd status failed");
112    CHECK_AND_RETURN_RET_LOG(
113        (static_cast<uint32_t>(flag) & static_cast<uint32_t>(O_WRONLY)) != static_cast<uint32_t>(O_WRONLY),
114        AVCS_ERR_INVALID_VAL, "Fd is not permitted to read");
115    CHECK_AND_RETURN_RET_LOG(lseek(fd, 0, SEEK_CUR) != -1, AVCS_ERR_INVALID_VAL, "Fd unseekable");
116
117    std::string uri = "fd://" + std::to_string(fd) + "?offset=" + \
118        std::to_string(offset) + "&size=" + std::to_string(size);
119
120    return InitWithURI(uri);
121}
122
123int32_t AVSourceImpl::InitWithDataSource(const std::shared_ptr<Media::IMediaDataSource> &dataSource)
124{
125    AVCODEC_SYNC_TRACE;
126
127    CHECK_AND_RETURN_RET_LOG(mediaDemuxer == nullptr, AVCS_ERR_INVALID_OPERATION, "Has been used by demuxer");
128    mediaDemuxer = std::make_shared<MediaDemuxer>();
129    mediaDemuxer->SetPlayerId("AVSource_Data");
130    CHECK_AND_RETURN_RET_LOG(mediaDemuxer != nullptr, AVCS_ERR_INVALID_OPERATION, "Create mediaDemuxer failed");
131
132    std::shared_ptr<MediaSource> mediaSource = std::make_shared<MediaSource>(dataSource);
133    Status ret = mediaDemuxer->SetDataSource(mediaSource);
134    CHECK_AND_RETURN_RET_LOG(ret == Status::OK, StatusToAVCodecServiceErrCode(ret), "Set data source failed");
135
136    return AVCS_ERR_OK;
137}
138
139AVSourceImpl::AVSourceImpl()
140{
141    AVCODEC_LOGD("Create instances 0x%{public}06" PRIXPTR, FAKE_POINTER(this));
142}
143
144AVSourceImpl::~AVSourceImpl()
145{
146    if (mediaDemuxer != nullptr) {
147        mediaDemuxer = nullptr;
148    }
149    AVCODEC_LOGD("Destroy instances 0x%{public}06" PRIXPTR, FAKE_POINTER(this));
150}
151
152int32_t AVSourceImpl::GetSourceFormat(OHOS::Media::Format &format)
153{
154    AVCODEC_SYNC_TRACE;
155    AVCODEC_LOGD("Get source format");
156
157    CHECK_AND_RETURN_RET_LOG(mediaDemuxer != nullptr, AVCS_ERR_INVALID_OPERATION, "MediaDemuxer does not exist");
158
159    std::shared_ptr<OHOS::Media::Meta> mediaInfo = mediaDemuxer->GetGlobalMetaInfo();
160    CHECK_AND_RETURN_RET_LOG(mediaInfo != nullptr, AVCS_ERR_INVALID_OPERATION, "Parse media info failed");
161
162    bool set = format.SetMeta(mediaInfo);
163    CHECK_AND_RETURN_RET_LOG(set, AVCS_ERR_INVALID_OPERATION, "Convert meta failed");
164
165    return AVCS_ERR_OK;
166}
167
168int32_t AVSourceImpl::GetTrackFormat(OHOS::Media::Format &format, uint32_t trackIndex)
169{
170    AVCODEC_SYNC_TRACE;
171    AVCODEC_LOGD("Get track %{public}u format", trackIndex);
172
173    CHECK_AND_RETURN_RET_LOG(mediaDemuxer != nullptr, AVCS_ERR_INVALID_OPERATION, "MediaDemuxer does not exist");
174
175    std::vector<std::shared_ptr<Meta>> streamsInfo = mediaDemuxer->GetStreamMetaInfo();
176    CHECK_AND_RETURN_RET_LOG(trackIndex < streamsInfo.size(), AVCS_ERR_INVALID_VAL,
177        "Just have %{public}zu tracks. index is out of range", streamsInfo.size());
178
179    bool set = format.SetMeta(streamsInfo[trackIndex]);
180    CHECK_AND_RETURN_RET_LOG(set, AVCS_ERR_INVALID_OPERATION, "Convert meta failed");
181
182    return AVCS_ERR_OK;
183}
184
185int32_t AVSourceImpl::GetUserMeta(OHOS::Media::Format &format)
186{
187    AVCODEC_SYNC_TRACE;
188    AVCODEC_LOGD("get user meta");
189
190    CHECK_AND_RETURN_RET_LOG(mediaDemuxer != nullptr, AVCS_ERR_INVALID_OPERATION, "MediaDemuxer does not exist");
191
192    std::shared_ptr<OHOS::Media::Meta> userDataMeta = mediaDemuxer->GetUserMeta();
193    CHECK_AND_RETURN_RET_LOG(userDataMeta != nullptr, AVCS_ERR_INVALID_OPERATION, "Parse user info failed");
194
195    bool set = format.SetMeta(userDataMeta);
196    CHECK_AND_RETURN_RET_LOG(set, AVCS_ERR_INVALID_OPERATION, "Convert meta failed");
197
198    return AVCS_ERR_OK;
199}
200} // namespace MediaAVCodec
201} // namespace OHOS