|
| 1 | +/****************************************************************************** |
| 2 | + QtAV: Media play library based on Qt and FFmpeg |
| 3 | + Copyright (C) 2013 Wang Bin <[email protected]> |
| 4 | +
|
| 5 | +* This file is part of QtAV |
| 6 | +
|
| 7 | + This library is free software; you can redistribute it and/or |
| 8 | + modify it under the terms of the GNU Lesser General Public |
| 9 | + License as published by the Free Software Foundation; either |
| 10 | + version 2.1 of the License, or (at your option) any later version. |
| 11 | +
|
| 12 | + This library is distributed in the hope that it will be useful, |
| 13 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 15 | + Lesser General Public License for more details. |
| 16 | +
|
| 17 | + You should have received a copy of the GNU Lesser General Public |
| 18 | + License along with this library; if not, write to the Free Software |
| 19 | + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| 20 | +******************************************************************************/ |
| 21 | + |
| 22 | +#include "QtAV/VideoDecoderFFmpeg.h" |
| 23 | +#include "private/VideoDecoderFFmpeg_p.h" |
| 24 | +#include <QtAV/Packet.h> |
| 25 | +#include <QtAV/QtAV_Compat.h> |
| 26 | +#include "prepost.h" |
| 27 | + |
| 28 | +#include <QDebug> |
| 29 | + |
| 30 | +#include <libavcodec/avcodec.h> |
| 31 | +extern "C" |
| 32 | +{ |
| 33 | + #include <libcedarv/libcedarv.h> |
| 34 | +} |
| 35 | + |
| 36 | +static void map32x32_to_yuv_Y(unsigned char* srcY, unsigned char* tarY, unsigned int coded_width, unsigned int coded_height) |
| 37 | +{ |
| 38 | + unsigned int i,j,l,m,n; |
| 39 | + unsigned int mb_width,mb_height,twomb_line,recon_width; |
| 40 | + unsigned long offset; |
| 41 | + unsigned char *ptr; |
| 42 | + |
| 43 | + ptr = srcY; |
| 44 | + mb_width = (coded_width+15)>>4; |
| 45 | + mb_height = (coded_height+15)>>4; |
| 46 | + twomb_line = (mb_height+1)>>1; |
| 47 | + recon_width = (mb_width+1)&0xfffffffe; |
| 48 | + |
| 49 | + for(i=0;i<twomb_line;i++) |
| 50 | + { |
| 51 | + for(j=0;j<recon_width;j+=2) |
| 52 | + { |
| 53 | + for(l=0;l<32;l++) |
| 54 | + { |
| 55 | + //first mb |
| 56 | + m=i*32 + l; |
| 57 | + n= j*16; |
| 58 | + if(m<coded_height && n<coded_width) |
| 59 | + { |
| 60 | + offset = m*coded_width + n; |
| 61 | + memcpy(tarY+offset,ptr,16); |
| 62 | + ptr += 16; |
| 63 | + } |
| 64 | + else |
| 65 | + ptr += 16; |
| 66 | + |
| 67 | + //second mb |
| 68 | + n= j*16+16; |
| 69 | + if(m<coded_height && n<coded_width) |
| 70 | + { |
| 71 | + offset = m*coded_width + n; |
| 72 | + memcpy(tarY+offset,ptr,16); |
| 73 | + ptr += 16; |
| 74 | + } |
| 75 | + else |
| 76 | + ptr += 16; |
| 77 | + } |
| 78 | + } |
| 79 | + } |
| 80 | +} |
| 81 | + |
| 82 | +static void map32x32_to_yuv_C(unsigned char* srcC,unsigned char* tarCb,unsigned char* tarCr,unsigned int coded_width,unsigned int coded_height) |
| 83 | +{ |
| 84 | + /* |
| 85 | + unsigned int i,j,k; |
| 86 | +
|
| 87 | + for (i = 0; i < coded_width; ++i) { |
| 88 | + k = i * coded_width; |
| 89 | + for (j = 0; j < coded_height; ++j) { |
| 90 | + *(tarCb + k) = srcC[2*k]; |
| 91 | + *(tarCr + k) = srcC[2*k+1]; |
| 92 | + k++; |
| 93 | + } |
| 94 | + } |
| 95 | + */ |
| 96 | + unsigned int i,j,l,m,n,k; |
| 97 | + unsigned int mb_width,mb_height,fourmb_line,recon_width; |
| 98 | + unsigned char line[16]; |
| 99 | + unsigned long offset; |
| 100 | + unsigned char *ptr; |
| 101 | + |
| 102 | + ptr = srcC; |
| 103 | + mb_width = (coded_width+7)>>3; |
| 104 | + mb_height = (coded_height+7)>>3; |
| 105 | + fourmb_line = (mb_height+3)>>2; |
| 106 | + recon_width = (mb_width+1)&0xfffffffe; |
| 107 | + |
| 108 | + for(i=0;i<fourmb_line;i++) |
| 109 | + { |
| 110 | + for(j=0;j<recon_width;j+=2) |
| 111 | + { |
| 112 | + for(l=0;l<32;l++) |
| 113 | + { |
| 114 | + //first mb |
| 115 | + m=i*32 + l; |
| 116 | + n= j*8; |
| 117 | + if(m<coded_height && n<coded_width) |
| 118 | + { |
| 119 | + offset = m*coded_width + n; |
| 120 | + memcpy(line,ptr,16); |
| 121 | + for(k=0;k<8;k++) |
| 122 | + { |
| 123 | + *(tarCb + offset + k) = line[2*k]; |
| 124 | + *(tarCr + offset + k) = line[2*k+1]; |
| 125 | + } |
| 126 | + ptr += 16; |
| 127 | + } |
| 128 | + else |
| 129 | + ptr += 16; |
| 130 | + |
| 131 | + //second mb |
| 132 | + n= j*8+8; |
| 133 | + if(m<coded_height && n<coded_width) |
| 134 | + { |
| 135 | + offset = m*coded_width + n; |
| 136 | + memcpy(line,ptr,16); |
| 137 | + for(k=0;k<8;k++) |
| 138 | + { |
| 139 | + *(tarCb + offset + k) = line[2*k]; |
| 140 | + *(tarCr + offset + k) = line[2*k+1]; |
| 141 | + } |
| 142 | + ptr += 16; |
| 143 | + } |
| 144 | + else |
| 145 | + ptr += 16; |
| 146 | + } |
| 147 | + } |
| 148 | + } |
| 149 | +} |
| 150 | + |
| 151 | +namespace QtAV { |
| 152 | + |
| 153 | +class VideoDecoderCedarvPrivate; |
| 154 | +class VideoDecoderCedarv : public VideoDecoderFFmpeg |
| 155 | +{ |
| 156 | + DPTR_DECLARE_PRIVATE(VideoDecoderCedarv) |
| 157 | +public: |
| 158 | + VideoDecoderCedarv(); |
| 159 | + bool prepare(); |
| 160 | + bool decode(const QByteArray &encoded); |
| 161 | + VideoFrame frame(); |
| 162 | +}; |
| 163 | + |
| 164 | +extern VideoDecoderId VideoDecoderId_Cedarv; |
| 165 | +FACTORY_REGISTER_ID_AUTO(VideoDecoder, Cedarv, "Cedarv") |
| 166 | + |
| 167 | +void RegisterVideoDecoderCedarv_Man() |
| 168 | +{ |
| 169 | + FACTORY_REGISTER_ID_MAN(VideoDecoder, Cedarv, "Cedarv") |
| 170 | +} |
| 171 | + |
| 172 | +class VideoDecoderCedarvPrivate : public VideoDecoderFFmpegPrivate |
| 173 | +{ |
| 174 | +public: |
| 175 | + VideoDecoderCedarvPrivate() { |
| 176 | + cedarv = 0; |
| 177 | + } |
| 178 | + |
| 179 | + ~VideoDecoderCedarvPrivate() { |
| 180 | + //TODO: |
| 181 | + } |
| 182 | + |
| 183 | + CEDARV_DECODER *cedarv; |
| 184 | + cedarv_picture_t cedarPicture; |
| 185 | + QByteArray y; |
| 186 | + QByteArray u; |
| 187 | + QByteArray v; |
| 188 | +}; |
| 189 | + |
| 190 | +VideoDecoderCedarv::VideoDecoderCedarv() |
| 191 | + : VideoDecoderFFmpeg(*new VideoDecoderCedarvPrivate()) |
| 192 | +{ |
| 193 | +} |
| 194 | + |
| 195 | + |
| 196 | +bool VideoDecoderCedarv::prepare() |
| 197 | +{ |
| 198 | + DPTR_D(VideoDecoderCedarv); |
| 199 | + if (!d.cedarv) { |
| 200 | + int ret; |
| 201 | + d.cedarv = libcedarv_init(&ret); |
| 202 | + if (ret < 0 || d.cedarv == NULL) |
| 203 | + return false; |
| 204 | + } |
| 205 | + |
| 206 | + d.codec_ctx->opaque = &d; //is it ok? |
| 207 | + |
| 208 | + cedarv_stream_info_t cedarStreamInfo; |
| 209 | + memset(&cedarStreamInfo, 0, sizeof cedarStreamInfo); |
| 210 | + |
| 211 | + switch (d.codec_ctx->codec_id) { |
| 212 | + case AV_CODEC_ID_H264: |
| 213 | + cedarStreamInfo.format = CEDARV_STREAM_FORMAT_H264; |
| 214 | + break; |
| 215 | + case AV_CODEC_ID_VP8: |
| 216 | + cedarStreamInfo.format = CEDARV_STREAM_FORMAT_VP8; |
| 217 | + break; |
| 218 | + case AV_CODEC_ID_VC1: |
| 219 | + cedarStreamInfo.format = CEDARV_STREAM_FORMAT_VC1; |
| 220 | + break; |
| 221 | + case AV_CODEC_ID_MPEG4: |
| 222 | + cedarStreamInfo.format = CEDARV_STREAM_FORMAT_MPEG4; |
| 223 | + cedarStreamInfo.sub_format = CEDARV_MPEG4_SUB_FORMAT_XVID; |
| 224 | + break; |
| 225 | + case AV_CODEC_ID_MPEG2VIDEO: |
| 226 | + cedarStreamInfo.format = CEDARV_STREAM_FORMAT_MPEG2; |
| 227 | + break; |
| 228 | + case AV_CODEC_ID_RV40: |
| 229 | + cedarStreamInfo.format = CEDARV_STREAM_FORMAT_REALVIDEO; |
| 230 | + break; |
| 231 | + default: |
| 232 | + return false; |
| 233 | + } |
| 234 | + cedarStreamInfo.video_width = d.codec_ctx->width; |
| 235 | + cedarStreamInfo.video_height = d.codec_ctx->height; |
| 236 | + if (d.codec_ctx->extradata_size) { |
| 237 | + cedarStreamInfo.init_data = d.codec_ctx->extradata; |
| 238 | + cedarStreamInfo.init_data_len = d.codec_ctx->extradata_size; |
| 239 | + } |
| 240 | + |
| 241 | + int cedarvRet; |
| 242 | + cedarvRet = d.cedarv->set_vstream_info(d.cedarv, &cedarStreamInfo); |
| 243 | + if (cedarvRet < 0) |
| 244 | + return false; |
| 245 | + cedarvRet = d.cedarv->open(d.cedarv); |
| 246 | + if (cedarvRet < 0) |
| 247 | + return false; |
| 248 | + |
| 249 | + d.cedarv->ioctrl(d.cedarv, CEDARV_COMMAND_PLAY, 0); |
| 250 | + |
| 251 | + return true; |
| 252 | +} |
| 253 | + |
| 254 | +bool VideoDecoderCedarv::decode(const QByteArray &encoded) |
| 255 | +{ |
| 256 | + DPTR_D(VideoDecoderCedarv); |
| 257 | + |
| 258 | + //d.cedarv->ioctrl(d.cedarv, CEDARV_COMMAND_JUMP, 0); |
| 259 | + |
| 260 | + AVPacket packet; |
| 261 | + av_new_packet(&packet, encoded.size()); |
| 262 | + memcpy(packet.data, encoded.data(), encoded.size()); |
| 263 | + |
| 264 | + if (packet.size == 0) { |
| 265 | + return true; |
| 266 | + } |
| 267 | + |
| 268 | + u32 bufsize0, bufsize1; |
| 269 | + u8 *buf0, *buf1; |
| 270 | + |
| 271 | + if (d.cedarv->request_write(d.cedarv, packet.size, &buf0, &bufsize0, &buf1, &bufsize1) >= 0) { |
| 272 | + memcpy(buf0, packet.data, bufsize0); |
| 273 | + if ((u32)packet.size > bufsize0) { |
| 274 | + memcpy(buf1, packet.data + bufsize0, bufsize1); |
| 275 | + } |
| 276 | + cedarv_stream_data_info_t stream_data_info; |
| 277 | + stream_data_info.type = 0; |
| 278 | + stream_data_info.lengh = packet.size; |
| 279 | + stream_data_info.pts = packet.pts; |
| 280 | + stream_data_info.flags = CEDARV_FLAG_FIRST_PART | CEDARV_FLAG_LAST_PART | CEDARV_FLAG_PTS_VALID; |
| 281 | + d.cedarv->update_data(d.cedarv, &stream_data_info); |
| 282 | + if (d.cedarv->decode(d.cedarv) >= 0 && !d.cedarv->display_request(d.cedarv, &d.cedarPicture)) { |
| 283 | + } |
| 284 | + else { |
| 285 | + if (d.cedarPicture.id) { |
| 286 | + d.cedarv->display_release(d.cedarv, d.cedarPicture.id); |
| 287 | + d.cedarPicture.id = 0; |
| 288 | + } |
| 289 | + } |
| 290 | + } |
| 291 | + return true; |
| 292 | +} |
| 293 | + |
| 294 | + |
| 295 | +VideoFrame VideoDecoderCedarv::frame() |
| 296 | +{ |
| 297 | + DPTR_D(VideoDecoderCedarv); |
| 298 | + if (!d.cedarPicture.id) { |
| 299 | + return VideoFrame(); |
| 300 | + } |
| 301 | + VideoFrame frame = VideoFrame(d.cedarPicture.width, d.cedarPicture.height, VideoFormat(VideoFormat::Format_YUV420P)); |
| 302 | + if ((unsigned int)d.y.size() != d.cedarPicture.size_y) { |
| 303 | + d.y.resize(d.cedarPicture.size_y); |
| 304 | + } |
| 305 | + if ((unsigned int)d.u.size() != d.cedarPicture.size_u / 2) { |
| 306 | + d.u.resize(d.cedarPicture.size_u / 2); |
| 307 | + } |
| 308 | + if ((unsigned int)d.v.size() != d.cedarPicture.size_u / 2) { |
| 309 | + d.v.resize(d.cedarPicture.size_u / 2); |
| 310 | + } |
| 311 | + int bitsPerLine_Y = d.cedarPicture.size_y / d.cedarPicture.height; |
| 312 | + int bitsPerRow_Y = d.cedarPicture.size_y / bitsPerLine_Y; |
| 313 | + map32x32_to_yuv_Y(d.cedarPicture.y, (uchar *)d.y.data(), bitsPerLine_Y, bitsPerRow_Y); |
| 314 | + map32x32_to_yuv_C(d.cedarPicture.u, (uchar *)d.u.data(), (uchar *)d.v.data(), bitsPerLine_Y / 2, bitsPerRow_Y / 2); |
| 315 | + frame.setBits((uchar *)d.y.data(), 0); |
| 316 | + frame.setBytesPerLine(d.cedarPicture.size_y / d.cedarPicture.height, 0); |
| 317 | + frame.setBits((uchar *)d.u.data(), 1); |
| 318 | + frame.setBytesPerLine(bitsPerLine_Y / 2, 1); |
| 319 | + frame.setBits((uchar *)d.v.data(), 2); |
| 320 | + frame.setBytesPerLine(bitsPerLine_Y / 2, 2); |
| 321 | + |
| 322 | + d.cedarv->display_release(d.cedarv, d.cedarPicture.id); |
| 323 | + d.cedarPicture.id = 0; |
| 324 | + return frame; |
| 325 | +} |
| 326 | + |
| 327 | + |
| 328 | +} // namespace QtAV |
0 commit comments