• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
16 #include "codec_utils.h"
17 #include "avcodec_log.h"
18 #include "media_description.h"
19 namespace OHOS {
20 namespace MediaAVCodec {
21 namespace Codec {
22 namespace {
23 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_FRAMEWORK, "FCodec"};
24 constexpr uint32_t INDEX_ARRAY = 2;
25 std::map<VideoPixelFormat, AVPixelFormat> g_pixelFormatMap = {
26     {VideoPixelFormat::YUVI420, AV_PIX_FMT_YUV420P},
27     {VideoPixelFormat::NV12, AV_PIX_FMT_NV12},
28     {VideoPixelFormat::NV21, AV_PIX_FMT_NV21},
29     {VideoPixelFormat::RGBA, AV_PIX_FMT_RGBA},
30 };
31 } // namespace
32 
33 using namespace OHOS::Media;
ConvertVideoFrame(std::shared_ptr<Scale> * scale,std::shared_ptr<AVFrame> frame,uint8_t ** dstData,int32_t * dstLineSize,AVPixelFormat dstPixFmt)34 int32_t ConvertVideoFrame(std::shared_ptr<Scale> *scale, std::shared_ptr<AVFrame> frame, uint8_t **dstData,
35                           int32_t *dstLineSize, AVPixelFormat dstPixFmt)
36 {
37     if (*scale == nullptr) {
38         *scale = std::make_shared<Scale>();
39         ScalePara scalePara{static_cast<int32_t>(frame->width),        static_cast<int32_t>(frame->height),
40                             static_cast<AVPixelFormat>(frame->format), static_cast<int32_t>(frame->width),
41                             static_cast<int32_t>(frame->height),       dstPixFmt};
42         CHECK_AND_RETURN_RET_LOG((*scale)->Init(scalePara, dstData, dstLineSize) == AVCS_ERR_OK, AVCS_ERR_UNKNOWN,
43                                  "Scale init error");
44     }
45     return (*scale)->Convert(frame->data, frame->linesize, dstData, dstLineSize);
46 }
47 
WriteYuvDataStride(const std::shared_ptr<AVMemory> & memory,uint8_t ** scaleData,const int32_t * scaleLineSize,int32_t stride,const Format & format)48 int32_t WriteYuvDataStride(const std::shared_ptr<AVMemory> &memory, uint8_t **scaleData, const int32_t *scaleLineSize,
49                            int32_t stride, const Format &format)
50 {
51     int32_t height;
52     int32_t fmt;
53     format.GetIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, height);
54     format.GetIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, fmt);
55     VideoPixelFormat pixFmt = static_cast<VideoPixelFormat>(fmt);
56     CHECK_AND_RETURN_RET_LOG(pixFmt == VideoPixelFormat::YUVI420 || pixFmt == VideoPixelFormat::NV12 ||
57                                  pixFmt == VideoPixelFormat::NV21,
58                              AVCS_ERR_UNSUPPORT, "pixFmt: %{public}d do not support", pixFmt);
59     int32_t srcPos = 0;
60     int32_t dstPos = 0;
61     int32_t dataSize = scaleLineSize[0];
62     int32_t writeSize = dataSize > stride ? stride : dataSize;
63     for (int32_t colNum = 0; colNum < height; colNum++) {
64         memory->Write(scaleData[0] + srcPos, writeSize, dstPos);
65         dstPos += stride;
66         srcPos += dataSize;
67     }
68     srcPos = 0;
69     if (pixFmt == VideoPixelFormat::YUVI420) {
70         dataSize = scaleLineSize[1];
71         writeSize = dataSize > (stride / UV_SCALE_FACTOR) ? (stride / UV_SCALE_FACTOR) : dataSize;
72         for (int32_t colNum = 0; colNum < (height / UV_SCALE_FACTOR); colNum++) {
73             memory->Write(scaleData[1] + srcPos, writeSize, dstPos);
74             dstPos += (stride / UV_SCALE_FACTOR);
75             srcPos += dataSize;
76         }
77         srcPos = 0;
78         for (int32_t colNum = 0; colNum < (height / UV_SCALE_FACTOR); colNum++) {
79             memory->Write(scaleData[INDEX_ARRAY] + srcPos, writeSize, dstPos);
80             dstPos += (stride / UV_SCALE_FACTOR);
81             srcPos += dataSize;
82         }
83     } else if ((pixFmt == VideoPixelFormat::NV12) || (pixFmt == VideoPixelFormat::NV21)) {
84         dataSize = scaleLineSize[1];
85         writeSize = dataSize > stride ? stride : dataSize;
86         for (int32_t colNum = 0; colNum < (height / UV_SCALE_FACTOR); colNum++) {
87             memory->Write(scaleData[1] + srcPos, writeSize, dstPos);
88             dstPos += stride;
89             srcPos += dataSize;
90         }
91     }
92     AVCODEC_LOGD("WriteYuvDataStride success");
93     return AVCS_ERR_OK;
94 }
95 
WriteRgbDataStride(const std::shared_ptr<AVMemory> & memory,uint8_t ** scaleData,const int32_t * scaleLineSize,int32_t stride,const Format & format)96 int32_t WriteRgbDataStride(const std::shared_ptr<AVMemory> &memory, uint8_t **scaleData, const int32_t *scaleLineSize,
97                            int32_t stride, const Format &format)
98 {
99     int32_t height;
100     format.GetIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, height);
101     int32_t srcPos = 0;
102     int32_t dstPos = 0;
103     int32_t dataSize = scaleLineSize[0];
104     int32_t writeSize = dataSize > stride ? stride : dataSize;
105     for (int32_t colNum = 0; colNum < height; colNum++) {
106         memory->Write(scaleData[0] + srcPos, writeSize, dstPos);
107         dstPos += stride;
108         srcPos += dataSize;
109     }
110 
111     AVCODEC_LOGD("WriteRgbDataStride success");
112     return AVCS_ERR_OK;
113 }
114 
WriteYuvData(const std::shared_ptr<AVMemory> & memory,uint8_t ** scaleData,const int32_t * scaleLineSize,int32_t & height,VideoPixelFormat & pixFmt)115 int32_t WriteYuvData(const std::shared_ptr<AVMemory> &memory, uint8_t **scaleData, const int32_t *scaleLineSize,
116                      int32_t &height, VideoPixelFormat &pixFmt)
117 {
118     int32_t ySize = static_cast<int32_t>(scaleLineSize[0] * height);      // yuv420: 411 nv21
119     int32_t uvSize = static_cast<int32_t>(scaleLineSize[1] * height / 2); // 2
120     int32_t frameSize = 0;
121     if (pixFmt == VideoPixelFormat::YUVI420) {
122         frameSize = ySize + (uvSize * 2); // 2
123     } else if (pixFmt == VideoPixelFormat::NV21 || pixFmt == VideoPixelFormat::NV12) {
124         frameSize = ySize + uvSize;
125     }
126     CHECK_AND_RETURN_RET_LOG(memory->GetCapacity() >= frameSize, AVCS_ERR_NO_MEMORY,
127                              "output buffer size is not enough: real[%{public}d], need[%{public}u]",
128                              memory->GetCapacity(), frameSize);
129     if (pixFmt == VideoPixelFormat::YUVI420) {
130         memory->Write(scaleData[0], ySize);
131         memory->Write(scaleData[1], uvSize);
132         memory->Write(scaleData[2], uvSize); // 2
133     } else if ((pixFmt == VideoPixelFormat::NV12) || (pixFmt == VideoPixelFormat::NV21)) {
134         memory->Write(scaleData[0], ySize);
135         memory->Write(scaleData[1], uvSize);
136     } else {
137         return AVCS_ERR_UNSUPPORT;
138     }
139     return AVCS_ERR_OK;
140 }
141 
WriteRgbData(const std::shared_ptr<AVMemory> & memory,uint8_t ** scaleData,const int32_t * scaleLineSize,int32_t & height)142 int32_t WriteRgbData(const std::shared_ptr<AVMemory> &memory, uint8_t **scaleData, const int32_t *scaleLineSize,
143                      int32_t &height)
144 {
145     int32_t frameSize = static_cast<int32_t>(scaleLineSize[0] * height);
146     CHECK_AND_RETURN_RET_LOG(memory->GetCapacity() >= frameSize, AVCS_ERR_NO_MEMORY,
147                              "output buffer size is not enough: real[%{public}d], need[%{public}u]",
148                              memory->GetCapacity(), frameSize);
149     memory->Write(scaleData[0], frameSize);
150     return AVCS_ERR_OK;
151 }
152 
WriteSurfaceData(const std::shared_ptr<AVMemory> & memory,struct SurfaceInfo & surfaceInfo,const Format & format)153 int32_t WriteSurfaceData(const std::shared_ptr<AVMemory> &memory, struct SurfaceInfo &surfaceInfo, const Format &format)
154 {
155     int32_t height;
156     int32_t fmt;
157     CHECK_AND_RETURN_RET_LOG(format.GetIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, height) && height > 0,
158                              AVCS_ERR_INVALID_VAL, "Invalid height %{public}d!", height);
159     CHECK_AND_RETURN_RET_LOG(format.GetIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, fmt) &&
160                              fmt >= static_cast<int32_t>(VideoPixelFormat::YUV420P) &&
161                              fmt <= static_cast<int32_t>(VideoPixelFormat::RGBA),
162                              AVCS_ERR_INVALID_VAL, "Cannot get pixel format");
163     VideoPixelFormat pixFmt = static_cast<VideoPixelFormat>(fmt);
164     if (surfaceInfo.surfaceFence != nullptr) {
165         surfaceInfo.surfaceFence->Wait(100); // 100ms
166     }
167     uint32_t yScaleLineSize = static_cast<uint32_t>(surfaceInfo.scaleLineSize[0]);
168     if (IsYuvFormat(pixFmt)) {
169         if (surfaceInfo.surfaceStride % yScaleLineSize) {
170             return WriteYuvDataStride(memory, surfaceInfo.scaleData, surfaceInfo.scaleLineSize,
171                                       surfaceInfo.surfaceStride, format);
172         }
173         WriteYuvData(memory, surfaceInfo.scaleData, surfaceInfo.scaleLineSize, height, pixFmt);
174     } else if (IsRgbFormat(pixFmt)) {
175         if (surfaceInfo.surfaceStride % yScaleLineSize) {
176             return WriteRgbDataStride(memory, surfaceInfo.scaleData, surfaceInfo.scaleLineSize,
177                                       surfaceInfo.surfaceStride, format);
178         }
179         WriteRgbData(memory, surfaceInfo.scaleData, surfaceInfo.scaleLineSize, height);
180     } else {
181         AVCODEC_LOGE("Fill frame buffer failed : unsupported pixel format: %{public}d", pixFmt);
182         return AVCS_ERR_UNSUPPORT;
183     }
184     return AVCS_ERR_OK;
185 }
186 
WriteBufferData(const std::shared_ptr<AVMemory> & memory,uint8_t ** scaleData,int32_t * scaleLineSize,const Format & format)187 int32_t WriteBufferData(const std::shared_ptr<AVMemory> &memory, uint8_t **scaleData, int32_t *scaleLineSize,
188                         const Format &format)
189 {
190     int32_t height;
191     int32_t width;
192     int32_t fmt;
193     CHECK_AND_RETURN_RET_LOG(format.GetIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, height) && height > 0,
194                              AVCS_ERR_INVALID_VAL, "Invalid height %{public}d!", height);
195     CHECK_AND_RETURN_RET_LOG(format.GetIntValue(MediaDescriptionKey::MD_KEY_WIDTH, width) && width > 0,
196                              AVCS_ERR_INVALID_VAL, "Invalid width %{public}d!", width);
197     CHECK_AND_RETURN_RET_LOG(format.GetIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, fmt) &&
198                              fmt >= static_cast<int32_t>(VideoPixelFormat::YUV420P) &&
199                              fmt <= static_cast<int32_t>(VideoPixelFormat::RGBA),
200                              AVCS_ERR_INVALID_VAL, "Cannot get pixel format");
201     VideoPixelFormat pixFmt = static_cast<VideoPixelFormat>(fmt);
202 
203     if (IsYuvFormat(pixFmt)) {
204         if (scaleLineSize[0] % width) {
205             return WriteYuvDataStride(memory, scaleData, scaleLineSize, width, format);
206         }
207         WriteYuvData(memory, scaleData, scaleLineSize, height, pixFmt);
208     } else if (IsRgbFormat(pixFmt)) {
209         if (scaleLineSize[0] % width) {
210             return WriteRgbDataStride(memory, scaleData, scaleLineSize, width * VIDEO_PIX_DEPTH_RGBA, format);
211         }
212         WriteRgbData(memory, scaleData, scaleLineSize, height);
213     } else {
214         AVCODEC_LOGE("Fill frame buffer failed : unsupported pixel format: %{public}d", pixFmt);
215         return AVCS_ERR_UNSUPPORT;
216     }
217     return AVCS_ERR_OK;
218 }
219 
AVStrError(int errnum)220 std::string AVStrError(int errnum)
221 {
222     char errbuf[AV_ERROR_MAX_STRING_SIZE] = {0};
223     av_strerror(errnum, errbuf, AV_ERROR_MAX_STRING_SIZE);
224     return std::string(errbuf);
225 }
226 
TranslateSurfaceRotation(const VideoRotation & rotation)227 GraphicTransformType TranslateSurfaceRotation(const VideoRotation &rotation)
228 {
229     switch (rotation) {
230         case VideoRotation::VIDEO_ROTATION_90: {
231             return GRAPHIC_ROTATE_270;
232         }
233         case VideoRotation::VIDEO_ROTATION_180: {
234             return GRAPHIC_ROTATE_180;
235         }
236         case VideoRotation::VIDEO_ROTATION_270: {
237             return GRAPHIC_ROTATE_90;
238         }
239         default:
240             return GRAPHIC_ROTATE_NONE;
241     }
242 }
243 
TranslateSurfaceFormat(const VideoPixelFormat & surfaceFormat)244 GraphicPixelFormat TranslateSurfaceFormat(const VideoPixelFormat &surfaceFormat)
245 {
246     switch (surfaceFormat) {
247         case VideoPixelFormat::YUVI420: {
248             return GraphicPixelFormat::GRAPHIC_PIXEL_FMT_YCBCR_420_P;
249         }
250         case VideoPixelFormat::RGBA: {
251             return GraphicPixelFormat::GRAPHIC_PIXEL_FMT_RGBA_8888;
252         }
253         case VideoPixelFormat::NV12: {
254             return GraphicPixelFormat::GRAPHIC_PIXEL_FMT_YCBCR_420_SP;
255         }
256         case VideoPixelFormat::NV21: {
257             return GraphicPixelFormat::GRAPHIC_PIXEL_FMT_YCRCB_420_SP;
258         }
259         default:
260             return GraphicPixelFormat::GRAPHIC_PIXEL_FMT_BUTT;
261     }
262 }
263 
ConvertPixelFormatFromFFmpeg(int32_t ffmpegPixelFormat)264 VideoPixelFormat ConvertPixelFormatFromFFmpeg(int32_t ffmpegPixelFormat)
265 {
266     auto iter = std::find_if(
267         g_pixelFormatMap.begin(), g_pixelFormatMap.end(),
268         [&](const std::pair<VideoPixelFormat, AVPixelFormat> &tmp) -> bool { return tmp.second == ffmpegPixelFormat; });
269     return iter == g_pixelFormatMap.end() ? VideoPixelFormat::UNKNOWN : iter->first;
270 }
271 
ConvertPixelFormatToFFmpeg(VideoPixelFormat pixelFormat)272 AVPixelFormat ConvertPixelFormatToFFmpeg(VideoPixelFormat pixelFormat)
273 {
274     auto iter = std::find_if(
275         g_pixelFormatMap.begin(), g_pixelFormatMap.end(),
276         [&](const std::pair<VideoPixelFormat, AVPixelFormat> &tmp) -> bool { return tmp.first == pixelFormat; });
277     return iter == g_pixelFormatMap.end() ? AV_PIX_FMT_NONE : iter->second;
278 }
279 
IsYuvFormat(VideoPixelFormat & format)280 bool IsYuvFormat(VideoPixelFormat &format)
281 {
282     return (format == VideoPixelFormat::YUVI420 || format == VideoPixelFormat::NV12 ||
283             format == VideoPixelFormat::NV21);
284 }
285 
IsRgbFormat(VideoPixelFormat & format)286 bool IsRgbFormat(VideoPixelFormat &format)
287 {
288     return (format == VideoPixelFormat::RGBA);
289 }
290 
Init(const ScalePara & scalePara,uint8_t ** dstData,int32_t * dstLineSize)291 int32_t Scale::Init(const ScalePara &scalePara, uint8_t **dstData, int32_t *dstLineSize)
292 {
293     scalePara_ = scalePara;
294     if (swsCtx_ != nullptr) {
295         return AVCS_ERR_OK;
296     }
297     auto swsContext =
298         sws_getContext(scalePara_.srcWidth, scalePara_.srcHeight, scalePara_.srcFfFmt, scalePara_.dstWidth,
299                        scalePara_.dstHeight, scalePara_.dstFfFmt, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
300     if (swsContext == nullptr) {
301         return AVCS_ERR_UNKNOWN;
302     }
303     swsCtx_ = std::shared_ptr<SwsContext>(swsContext, [](struct SwsContext *ptr) {
304         if (ptr != nullptr) {
305             sws_freeContext(ptr);
306         }
307     });
308     auto ret = av_image_alloc(dstData, dstLineSize, scalePara_.dstWidth, scalePara_.dstHeight, scalePara_.dstFfFmt,
309                               scalePara_.align);
310     if (ret < 0) {
311         return AVCS_ERR_UNKNOWN;
312     }
313     for (int32_t i = 0; dstLineSize[i] > 0; i++) {
314         if (dstData[i] && !dstLineSize[i]) {
315             return AVCS_ERR_UNKNOWN;
316         }
317     }
318     return AVCS_ERR_OK;
319 }
320 
Convert(uint8_t ** srcData,const int32_t * srcLineSize,uint8_t ** dstData,int32_t * dstLineSize)321 int32_t Scale::Convert(uint8_t **srcData, const int32_t *srcLineSize, uint8_t **dstData, int32_t *dstLineSize)
322 {
323     auto res = sws_scale(swsCtx_.get(), srcData, srcLineSize, 0, scalePara_.srcHeight, dstData, dstLineSize);
324     if (res < 0) {
325         return AVCS_ERR_UNKNOWN;
326     }
327     return AVCS_ERR_OK;
328 }
329 } // namespace Codec
330 } // namespace MediaAVCodec
331 } // namespace OHOS