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