PageRenderTime 125ms CodeModel.GetById 41ms app.highlight 52ms RepoModel.GetById 28ms app.codeStats 0ms

/Avc/main.cpp

http://github.com/mbebenita/Broadway
C++ | 299 lines | 237 code | 51 blank | 11 comment | 41 complexity | 3c4a70ea3f68a95666cb4c3ee39f1d6f MD5 | raw file
  1#include <stdio.h>
  2#include <stdlib.h>
  3#include <SDL/SDL.h>
  4
  5#include "avcdec_int.h"
  6#include "avcdec_api.h"
  7
  8#include "yuv2rgb.h"
  9
 10#include "SDL/SDL.h"
 11
 12#define DEBUG_LOGGING 0
 13#if DEBUG_LOGGING
 14  #define DLOG printf
 15#else
 16  #define DLOG(...)
 17#endif
 18
 19#define RENDER 1
 20
 21#define FASTYUV2RGB 0
 22
 23// Globals
 24
 25SDL_Surface* screen = NULL;
 26AVCHandle decoder;
 27int size = 0;
 28uint8* stream = NULL;
 29uint8* buffer = NULL;
 30uint8 *nal_unit = NULL;
 31int nal_size;
 32
 33// Main loop handling
 34
 35enum mainLoopStatus {
 36  MLS_STOP = 0,
 37  MLS_CONTINUE = 1,
 38  MLS_FRAMERENDERED = 2
 39};
 40
 41// Runs the main loop. This is replaced in JavaScript with an asynchronous loop
 42// that calls mainLoopIteration
 43void runMainLoop();
 44mainLoopStatus mainLoopIteration();
 45
 46// Utilities
 47
 48char *readFile(const char* filename, int *size) {
 49    FILE *file = fopen(filename, "rb");
 50    if (!file) {
 51        fprintf(stderr, "Unable to open file %s\n", filename);
 52        return NULL;
 53    }
 54    fseek(file, 0, SEEK_END);
 55    unsigned long bufferSize = ftell(file) + 1;
 56    fseek(file, 0, SEEK_SET);
 57    char *buffer = (char *) malloc(bufferSize);
 58    if (!buffer) {
 59        fprintf(stderr, "Memory error!\n");
 60        fclose(file);
 61        return NULL;
 62    }
 63    fread((char *) buffer, bufferSize, 1, file);
 64    fclose(file);
 65    *size = (int) bufferSize;
 66    return buffer;
 67}
 68
 69typedef uintptr_t (*FunctionType_Malloc)(void *userData, int32 size,
 70        int attribute);
 71
 72uintptr_t my_malloc(void *userData, int32 size, int attribute) {
 73    return (uintptr_t) malloc(size);
 74}
 75
 76void my_free(void *userData, uintptr_t mem) {
 77    free((void *) mem);
 78}
 79
 80#ifdef LINUX
 81int main(int argc, char **argv) {
 82#else
 83int SDL_main(int argc, char **argv) {
 84#endif
 85
 86    decoder.AVCObject = NULL;
 87
 88    decoder.CBAVC_Malloc = my_malloc;
 89    decoder.CBAVC_Free = my_free;
 90    decoder.debugEnable = true;
 91
 92    size = 0;
 93
 94#if LINUX
 95    buffer = (uint8*) readFile(argc == 2 ? argv[1] : "../Media/mozilla.264", &size);
 96#else
 97    buffer = (uint8*) readFile(argc == 2 ? argv[1] : "../Media/matrix_large.h264", &size);
 98#endif
 99    stream = buffer;
100
101    nal_unit = NULL;
102    nal_size = size;
103
104#if RENDER
105    SDL_Init(SDL_INIT_VIDEO);
106#endif
107
108    runMainLoop();
109
110    return 0;
111}
112
113void runMainLoop() {
114    mainLoopStatus status;
115    while ((status = mainLoopIteration()) != MLS_STOP);
116}
117
118extern "C" float getPosition() {
119    int offset = stream - buffer;
120    return (float)offset / (float)size;
121}
122
123extern "C" void setPosition(float value) {
124    if (value < 0 || value > 1) {
125        return;
126    }
127
128    PVAVCDecReset(&decoder);
129    int offset = (int)((float)size * value);
130    stream = buffer + offset;
131    nal_size = size - offset;
132    int err = 0;
133
134    int nal_type = 0;
135    int nal_ref_idc = 0;
136
137    DLOG("Err: %d, %d\n", offset, nal_size);
138
139    while (nal_size > 0) {
140        int old = nal_size;
141        if ((err = PVAVCAnnexBGetNALUnit(stream, &nal_unit, &nal_size)) != AVCDEC_SUCCESS) {
142            DLOG("Err A: %d\n", err);
143            return;
144        }
145        if ((err = PVAVCDecGetNALType(nal_unit, nal_size, &nal_type, &nal_ref_idc)) == AVCDEC_SUCCESS) {
146            if (nal_type == AVC_NALTYPE_IDR) {
147                nal_size = old;
148                DLOG("Found next IDR Slice at: %X, nal_size %d\n", stream, nal_size);
149                break;
150            }
151        }
152        stream = nal_unit + nal_size;
153        nal_size = size - (stream - buffer);
154    }
155}
156
157extern "C" void paint(uint8 *luma, uint8 *cb, uint8 *cr, int width, int height) {
158    int chromaWidth = width >> 1;
159#if FASTYUV2RGB
160    uint8 *dst = (uint8 *)screen->pixels;
161    yuv420_2_rgb8888( (uint8*) dst, luma, cb, cr, width, height, width, chromaWidth, width << 2, yuv2rgb565_table, 0);
162#else
163    uint32 *dst = (uint32 *)screen->pixels;
164    for (int y = 0; y < height; y++) {
165        int lineOffLuma = y * width;
166        int lineOffChroma = (y >> 1) * chromaWidth;
167        for (int x = 0; x < width; x++) {
168            int c = luma[lineOffLuma + x] - 16;
169            int d = cb[lineOffChroma + (x >> 1)] - 128;
170            int e = cr[lineOffChroma + (x >> 1)] - 128;
171
172            int red = (298 * c + 409 * e + 128) >> 8;
173            red = red < 0 ? 0 : (red > 255 ? 255 : red);
174            int green = (298 * c - 100 * d - 208 * e + 128) >> 8;
175            green = green < 0 ? 0 : (green > 255 ? 255 : green);
176            int blue = (298 * c + 516 * d + 128) >> 8;
177            blue = blue < 0 ? 0 : (blue > 255 ? 255 : blue);
178            int alpha = 255;
179            dst[lineOffLuma + x] = SDL_MapRGB(screen->format, red & 0xff, green & 0xff, blue & 0xff);
180        }
181    }
182#endif
183}
184
185mainLoopStatus mainLoopIteration() {
186    int nal = 0;
187
188    DLOG("Looking for next NAL at: %X, nal_size %d\n", stream, nal_size);
189
190    if (PVAVCAnnexBGetNALUnit(stream, &nal_unit, &nal_size) != AVCDEC_SUCCESS) {
191#if RENDER
192        SDL_Quit();
193#endif
194        PVAVCCleanUpDecoder(&decoder);
195        return MLS_STOP;
196    }
197
198    mainLoopStatus status = MLS_CONTINUE;
199
200    DLOG("Decoded NAL Unit %d Size: %d\n", nal++, nal_size);
201    int nal_type = 0;
202    int nal_ref_idc = 0;
203
204    PVAVCDecGetNALType(nal_unit, nal_size, &nal_type, &nal_ref_idc);
205    DLOG("  nal_type: %d\n", nal_type);
206    DLOG("  nal_ref_idc: %d\n", nal_ref_idc);
207
208    if (nal_type == AVC_NALTYPE_SPS) {
209        DLOG("  SPS\n");
210        PVAVCDecSeqParamSet(&decoder, nal_unit, nal_size);
211    } else if (nal_type == AVC_NALTYPE_PPS) {
212        DLOG("  PPS\n");
213        PVAVCDecPicParamSet(&decoder, nal_unit, nal_size);
214    } else if (nal_type == AVC_NALTYPE_SLICE || nal_type == AVC_NALTYPE_IDR) {
215        DLOG("  SLICE\n");
216        int ret = PVAVCDecodeSlice(&decoder, nal_unit, nal_size);
217        DLOG("  SLICE %d\n", ret);
218
219        int indx;
220        int release;
221        AVCFrameIO output;
222        PVAVCDecGetOutput(&decoder, &indx, &release, &output);
223
224#if RENDER
225        if (!screen) {
226            screen = SDL_SetVideoMode(output.pitch, output.height, 32, SDL_HWSURFACE | SDL_RESIZABLE);
227        }
228        SDL_LockSurface(screen);
229#else
230        if (!screen) {
231            screen = (SDL_Surface*)malloc(sizeof(SDL_Surface));
232            screen->pixels = malloc(output.pitch * output.height * 32);
233        }
234#endif
235
236
237#if !RENDER
238        int mean = 0;
239#endif
240
241#if RENDER
242        paint(output.YCbCr[0], output.YCbCr[1], output.YCbCr[2], output.pitch, output.height);
243#endif
244
245#if !RENDER
246        // printf("C mean: %d\n", mean/(output.height*output.pitch));
247#endif
248
249#if RENDER
250        SDL_UnlockSurface(screen);
251        SDL_Flip(screen);
252#else
253        static int frame = 0;
254        // printf("\n=== dumping frame %d ===\n\n", frame++);
255        int min = output.height < output.pitch ? output.height : output.pitch;
256        for (int y = 0; y < min; y++) {
257//            printf("%d: %d\n", y, ((char*)screen->pixels)[y*output.pitch + y*4]);
258        }
259        // if (frame == 100) exit(0);
260#endif
261        status = MLS_FRAMERENDERED;
262        DLOG("  DECODED %d\n", indx);
263
264#if RENDER
265#if !JS
266        SDL_Event event;
267        while (SDL_PollEvent(&event)) {
268            switch (event.type) {
269            case SDL_QUIT:
270                exit(0);
271                break;
272#if !LINUX
273            case SDL_KEYDOWN:
274                // printf("Key: %s\n", SDL_GetKeyName( event.key.keysym.sym ));
275                // printf("Key: %d\n", event.key.keysym.scancode);
276                if (event.key.keysym.scancode == 1) {
277                    setPosition(0.5f);
278                    return status;
279                } else {
280                    exit(0);
281                }
282                break;
283#endif
284            }
285        }
286#endif
287#endif
288    } else if (nal_type == AVC_NALTYPE_SEI) {
289        DLOG("  SPS\n");
290        PVAVCDecSEI(&decoder, nal_unit, nal_size);
291    } else {
292        printf("Skipped nal_type %d\n", nal_type);
293    }
294
295    stream = nal_unit + nal_size;
296    nal_size = size - (stream - buffer);
297
298    return status;
299}