├── .gitattributes ├── .gitignore ├── LICENSE ├── Mp4Decoder.cpp └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | 38 | # Directories potentially created on remote AFP share 39 | .AppleDB 40 | .AppleDesktop 41 | Network Trash Folder 42 | Temporary Items 43 | .apdisk 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Chih Cheng Yang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Mp4Decoder.cpp: -------------------------------------------------------------------------------- 1 |  2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | extern "C" { 12 | #include 13 | #include 14 | #include 15 | } 16 | 17 | 18 | #define MP4toRGB 1 19 | #define WRITE_RGB 0 20 | 21 | #define MP4toYUV 1 22 | #define WRITE_YUV 0 23 | 24 | typedef void (*decodeFrameCallback)( unsigned char *pRGBData , unsigned char *pYUVData, unsigned int nWidth, unsigned int nHeight ); 25 | 26 | 27 | void SaveFramePPM(uint8_t *pData_rgb, int width, int height, int iFrame) 28 | { 29 | if(iFrame>10) 30 | return; 31 | 32 | FILE *pFile; 33 | char szFilename[32]; 34 | int y; 35 | 36 | // Open file 37 | sprintf(szFilename, "%d.ppm", iFrame); 38 | pFile=fopen(szFilename, "wb"); 39 | if(pFile==NULL) 40 | return; 41 | 42 | // Write header 43 | fprintf(pFile, "P6\n%d %d\n255\n", width, height); 44 | 45 | // Write pixel data 46 | fwrite(pData_rgb, 1, height*width*3, pFile); 47 | 48 | // Close file 49 | fclose(pFile); 50 | } 51 | 52 | 53 | int Mp4Decoder( decodeFrameCallback cb){ 54 | 55 | av_register_all(); 56 | 57 | AVFormatContext *pFormatCtx; 58 | 59 | pFormatCtx = avformat_alloc_context(); 60 | 61 | char filepath[] = "1421735998235.mp4"; 62 | 63 | if (avformat_open_input(&pFormatCtx, filepath, NULL, NULL) != 0) { 64 | printf("Can't open the file\n"); 65 | return -1; 66 | } 67 | 68 | if (avformat_find_stream_info(pFormatCtx, NULL) < 0) { 69 | printf("Couldn't find stream information.\n"); 70 | return -1; 71 | } 72 | 73 | av_dump_format(pFormatCtx, 0, filepath, 0); 74 | 75 | // --------------------------------------------------------- // 76 | 77 | int i, videoIndex = -1; 78 | for (i = 0; i < pFormatCtx->nb_streams; i++) { 79 | if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { 80 | videoIndex = i; 81 | break; 82 | } 83 | } 84 | 85 | if (videoIndex == -1) 86 | return -1; 87 | // --------------------------------------------------------- // 88 | 89 | AVCodecContext *pCodecCtx; 90 | 91 | AVCodec *pCodec; 92 | 93 | pCodecCtx = pFormatCtx->streams[videoIndex]->codec; 94 | 95 | pCodec = avcodec_find_decoder(pCodecCtx->codec_id); 96 | if (pCodec == NULL) { 97 | printf("Unsupported codec!\n"); 98 | return -1; 99 | } 100 | 101 | if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) { 102 | printf("Could not open codec.\n"); 103 | return -1; 104 | } 105 | 106 | AVFrame *pFrame, *pFrameYUV; 107 | pFrame = av_frame_alloc(); 108 | pFrameYUV = av_frame_alloc(); 109 | 110 | uint8_t *out_buffer; 111 | int numBytes; 112 | numBytes = avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, 113 | pCodecCtx->height); 114 | 115 | out_buffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t)); 116 | 117 | avpicture_fill((AVPicture*) pFrameYUV, out_buffer, PIX_FMT_YUV420P, 118 | pCodecCtx->width, pCodecCtx->height); 119 | 120 | 121 | //*************************************************************// 122 | 123 | int frameFinished; 124 | AVPacket packet; 125 | av_new_packet(&packet, numBytes); 126 | int ret; 127 | 128 | static struct SwsContext *img_convert_ctx; 129 | 130 | //------------------------------------------------------// 131 | #if (MP4toRGB==0) 132 | img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, 133 | pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, 134 | PIX_FMT_YUV420P, 135 | SWS_BICUBIC, NULL, NULL, NULL); 136 | //--------------------------------------// 137 | #else 138 | img_convert_ctx = sws_getContext( pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, 139 | pCodecCtx->width, pCodecCtx->height, PIX_FMT_RGB24, SWS_POINT, 140 | NULL, NULL, NULL); 141 | //------------------------------------- 142 | uint8_t *out_buffer_rgb; 143 | int numBytes_rgb; 144 | numBytes_rgb = avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width, 145 | pCodecCtx->height); 146 | out_buffer_rgb = (uint8_t *) av_malloc(numBytes_rgb * sizeof(uint8_t)); 147 | 148 | printf("numBytes_rgb %d\n",numBytes_rgb); 149 | //------------------------------------- 150 | uint8_t* outData_rgb[4]; 151 | int outLinesize_rgb[4]; 152 | //準備output的buffer pointer 153 | outData_rgb[0] = out_buffer_rgb; 154 | outData_rgb[1] = 155 | outData_rgb[2] = 156 | outData_rgb[3] = NULL; 157 | outLinesize_rgb[0] = pCodecCtx->width * 3; 158 | outLinesize_rgb[1] = outLinesize_rgb[2] = outLinesize_rgb[3] = 0; 159 | #endif 160 | //------------------------------------------------------// 161 | 162 | //store yuv 163 | //------------------------------------------------------// 164 | #if (MP4toYUV==1) 165 | #if (WRITE_YUV==1) 166 | FILE *pFile=fopen("output.yuv", "wb"); 167 | if(pFile == NULL) 168 | return -1; 169 | #endif 170 | //------------------------------------ 171 | uint8_t *out_buffer_yuv = (uint8_t*)_mm_malloc(pCodecCtx->width*pCodecCtx->height*2 ,16); 172 | //------------------------------------- 173 | #endif 174 | //------------------------------------------------------// 175 | 176 | while (av_read_frame(pFormatCtx, &packet) >= 0) { 177 | if (packet.stream_index == videoIndex) { 178 | ret = avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet); 179 | if (ret >= 0) { 180 | if (frameFinished) { 181 | //store yuv 182 | //------------------------------------------------------// 183 | #if (MP4toYUV==1) 184 | int i = 0; 185 | unsigned char *pFrameTemp; unsigned char *pYuvTemp=out_buffer_yuv; 186 | 187 | pFrameTemp = (unsigned char*)pFrame->data[0]; 188 | for (i = 0 ; i < pCodecCtx->height; i++){ 189 | #if (WRITE_YUV==1) 190 | fwrite(pFrameTemp + i * pFrame->linesize[0], 1, pCodecCtx->width, pFile); 191 | #endif 192 | memcpy(pYuvTemp, pFrameTemp + i * pFrame->linesize[0], pCodecCtx->width); 193 | pYuvTemp += pCodecCtx->width; 194 | } 195 | pFrameTemp = (unsigned char*)pFrame->data[1]; 196 | for (i = 0 ; i < pCodecCtx->height/2; i++){ 197 | #if (WRITE_YUV==1) 198 | fwrite(pFrameTemp + i * pFrame->linesize[1], 1, pCodecCtx->width/2, pFile); 199 | #endif 200 | memcpy(pYuvTemp, pFrameTemp + i * pFrame->linesize[1], pCodecCtx->width/2); 201 | pYuvTemp += pCodecCtx->width/2; 202 | } 203 | 204 | pFrameTemp = (unsigned char*)pFrame->data[2]; 205 | for (i = 0 ; i < pCodecCtx->height/2; i++){ 206 | #if (WRITE_YUV==1) 207 | fwrite(pFrameTemp + i * pFrame->linesize[2], 1, pCodecCtx->width/2, pFile); 208 | #endif 209 | memcpy(pYuvTemp, pFrameTemp + i * pFrame->linesize[2], pCodecCtx->width/2); 210 | pYuvTemp += pCodecCtx->width/2; 211 | } 212 | 213 | #endif 214 | //sws_scale RGB 215 | //------------------------------------------------------// 216 | #if (MP4toRGB==1) 217 | sws_scale(img_convert_ctx, (const uint8_t* const *) pFrame->data, pFrame->linesize , 0, 218 | pCodecCtx->height, outData_rgb, outLinesize_rgb); 219 | #endif 220 | //------------------------------------------------------// 221 | cb(out_buffer_rgb,out_buffer_yuv, pCodecCtx->width ,pCodecCtx->height); 222 | 223 | 224 | } 225 | } 226 | } 227 | av_free_packet(&packet); 228 | 229 | }// while (av_read_frame(pFormatCtx, &packet) >= 0) 230 | 231 | //*************************************************************// 232 | #if (MP4toRGB==1) 233 | av_free(out_buffer_rgb); 234 | #endif 235 | #if (MP4toYUV==1) 236 | _mm_free(out_buffer_yuv); 237 | #if (WRITE_YUV==1) 238 | fclose(pFile); 239 | #endif 240 | #endif 241 | av_frame_free(&pFrame); 242 | av_frame_free(&pFrameYUV); 243 | avcodec_close(pCodecCtx); 244 | avformat_close_input(&pFormatCtx); 245 | 246 | return 0; 247 | } 248 | //=========================================================== 249 | void decodeFrame( unsigned char *pRGBData , unsigned char *pYUVData, unsigned int nWidth, unsigned int nHeight ){ 250 | 251 | #if (WRITE_RGB==1) 252 | static int iFrame=0; 253 | SaveFramePPM(pRGBData, nWidth ,nHeight, iFrame); 254 | iFrame++; 255 | #endif 256 | } 257 | 258 | int _tmain(int argc, _TCHAR* argv[]) 259 | { 260 | 261 | Mp4Decoder( decodeFrame ); 262 | getchar(); 263 | return 0; 264 | 265 | } 266 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | c-Mp4Decoder 2 | ================ 3 | 4 | Mp4 decode to YUV or RGB.... 5 | 6 | Usage 7 | ================ 8 | 9 | ### Build 10 | 11 | ### Example 12 | 13 | ### Notice 14 | 15 | --------------------------------------------------------------------------------