static int granulepos_test_encode (int frequency, int auto_p) { theora_info ti; theora_state th; int result; int frame, tframe, keyframe, keydist; int shift; double rate, ttime; yuv_buffer yuv; unsigned char *framedata; ogg_packet op; long long int last_granule = -1; /* INFO ("+ Initializing theora_info struct"); */ theora_info_init (&ti); ti.width = 32; ti.height = 32; ti.frame_width = ti.width; ti.frame_height = ti.frame_height; ti.offset_x = 0; ti.offset_y = 0; ti.fps_numerator = 16; ti.fps_denominator = 1; ti.aspect_numerator = 1; ti.aspect_denominator = 1; ti.colorspace = OC_CS_UNSPECIFIED; ti.pixelformat = OC_PF_420; ti.target_bitrate = 0; ti.quality = 16; ti.dropframes_p = 0; ti.quick_p = 1; /* check variations of automatic or forced keyframe choice */ ti.keyframe_auto_p = auto_p; /* check with variations of the maximum gap */ ti.keyframe_frequency = frequency; ti.keyframe_frequency_force = frequency; ti.keyframe_data_target_bitrate = ti.target_bitrate * 1.5; ti.keyframe_auto_threshold = 80; ti.keyframe_mindistance = MIN(8, frequency); ti.noise_sensitivity = 1; /* INFO ("+ Initializing theora_state for encoding"); */ result = theora_encode_init (&th, &ti); if (result == OC_DISABLED) { INFO ("+ Clearing theora_state"); theora_clear (&th); } else if (result < 0) { FAIL ("negative return code initializing encoder"); } /* INFO ("+ Setting up dummy 4:2:0 frame data"); */ framedata = calloc(ti.height, ti.width); yuv.y_width = ti.width; yuv.y_height = ti.height; yuv.y_stride = ti.width; yuv.y = framedata; yuv.uv_width = ti.width / 2; yuv.uv_height = ti.width / 2; yuv.uv_stride = ti.width; yuv.u = framedata; yuv.v = framedata; INFO ("+ Checking granulepos generation"); shift = theora_granule_shift(&ti); rate = (double)ti.fps_denominator/ti.fps_numerator; for (frame = 0; frame < frequency * 2 + 1; frame++) { result = theora_encode_YUVin (&th, &yuv); if (result < 0) { printf("theora_encode_YUVin() returned %d\n", result); FAIL ("negative error code submitting frame for compression"); } theora_encode_packetout (&th, frame >= frequency * 2, &op); if ((long long int)op.granulepos < last_granule) FAIL ("encoder returned a decreasing granulepos value"); last_granule = op.granulepos; keyframe = op.granulepos >> shift; keydist = op.granulepos - (keyframe << shift); tframe = theora_granule_frame (&th, op.granulepos); ttime = theora_granule_time(&th, op.granulepos); #if DEBUG printf("++ frame %d granulepos %lld %d:%d %d %.3lfs\n", frame, (long long int)op.granulepos, keyframe, keydist, tframe, theora_granule_time (&th, op.granulepos)); #endif if ((keyframe + keydist) != frame + 1) FAIL ("encoder granulepos does not map to the correct frame number"); if (tframe != frame) FAIL ("theora_granule_frame returned incorrect results"); if (fabs(rate*(frame+1) - ttime) > 1.0e-6) FAIL ("theora_granule_time returned incorrect results"); } /* clean up */ /* INFO ("+ Freeing dummy frame data"); */ free (framedata); /* INFO ("+ Clearing theora_info struct"); */ theora_info_clear (&ti); /* INFO ("+ Clearing theora_state"); */ theora_clear (&th); return 0; }
static int OGV_LoadVideoFrame(cinematic_t *cin) { int r = 0; ogg_packet op; memset(&op, 0, sizeof(op)); while (!r && (ogg_stream_packetout(&g_ogm->os_video, &op))) { ogg_int64_t th_frame; theora_decode_packetin(&g_ogm->th_state, &op); th_frame = theora_granule_frame(&g_ogm->th_state, g_ogm->th_state.granulepos); if ((g_ogm->VFrameCount < th_frame && th_frame >= OGV_NextNeededVFrame(cin)) || !cin->frameBuffer[0]) { if (theora_decode_YUVout(&g_ogm->th_state, &g_ogm->th_yuvbuffer)) { continue; } if (cin->frameWidth != g_ogm->th_info.width || cin->frameHeight != g_ogm->th_info.height) { cin->frameWidth = g_ogm->th_info.width; cin->frameHeight = g_ogm->th_info.height; Com_DPrintf("Theora new resolution %dx%d\n", cin->frameWidth, cin->frameHeight); } if (cin->frameBufferSize < g_ogm->th_info.width * g_ogm->th_info.height) { cin->frameBufferSize = g_ogm->th_info.width * g_ogm->th_info.height; /* Free old output buffer */ if (cin->frameBuffer[0]) { Com_Dealloc(cin->frameBuffer[0]); cin->frameBuffer[0] = NULL; } /* Allocate the new buffer */ cin->frameBuffer[0] = (unsigned char *)Com_Allocate(cin->frameBufferSize * 4); if (cin->frameBuffer[0] == NULL) { cin->frameBufferSize = 0; r = -2; break; } } if (OGV_yuv_to_rgb24(&g_ogm->th_yuvbuffer, &g_ogm->th_info, (unsigned int *) cin->frameBuffer[0])) { r = 1; g_ogm->VFrameCount = th_frame; } else { r = -1; } } } return r; }
static int loadVideoFrameTheora(void) { int r = 0; ogg_packet op; memset(&op,0,sizeof(op)); while( !r && (ogg_stream_packetout(&g_ogm.os_video,&op)) ) { ogg_int64_t th_frame; theora_decode_packetin(&g_ogm.th_state, &op); th_frame = theora_granule_frame(&g_ogm.th_state,g_ogm.th_state.granulepos); if((g_ogm.VFrameCount<th_frame && th_frame>=nextNeededVFrame()) || !g_ogm.outputBuffer) { // int i,j; int yWShift, uvWShift; int yHShift, uvHShift; if( theora_decode_YUVout(&g_ogm.th_state, &g_ogm.th_yuvbuffer) ) continue; if(g_ogm.outputWidht != g_ogm.th_info.width || g_ogm.outputHeight != g_ogm.th_info.height) { g_ogm.outputWidht = g_ogm.th_info.width; g_ogm.outputHeight = g_ogm.th_info.height; Com_DPrintf("[Theora(ogg)]new resolution %dx%d\n",g_ogm.outputWidht,g_ogm.outputHeight); } if(g_ogm.outputBufferSize < g_ogm.th_info.width*g_ogm.th_info.height) { g_ogm.outputBufferSize = g_ogm.th_info.width*g_ogm.th_info.height; /* Free old output buffer*/ if(g_ogm.outputBuffer) free(g_ogm.outputBuffer); /* Allocate the new buffer */ g_ogm.outputBuffer = (unsigned char*)malloc(g_ogm.outputBufferSize*4); if(g_ogm.outputBuffer == NULL) { g_ogm.outputBufferSize = 0; r = -2; break; } } yWShift = findSizeShift(g_ogm.th_yuvbuffer.y_width, g_ogm.th_info.width); uvWShift = findSizeShift(g_ogm.th_yuvbuffer.uv_width, g_ogm.th_info.width); yHShift = findSizeShift(g_ogm.th_yuvbuffer.y_height, g_ogm.th_info.height); uvHShift = findSizeShift(g_ogm.th_yuvbuffer.uv_height,g_ogm.th_info.height); if(yWShift<0 || uvWShift<0 || yHShift<0 || uvHShift<0) { Com_Printf("[Theora] unexpected resolution in a yuv-Frame\n"); r = -1; } else { Frame_yuv_to_rgb24(g_ogm.th_yuvbuffer.y,g_ogm.th_yuvbuffer.u,g_ogm.th_yuvbuffer.v, g_ogm.th_info.width, g_ogm.th_info.height, g_ogm.th_yuvbuffer.y_stride, g_ogm.th_yuvbuffer.uv_stride, yWShift, uvWShift, yHShift, uvHShift, (unsigned int*)g_ogm.outputBuffer ); /* unsigned char* pixelPtr = g_ogm.outputBuffer; unsigned int* pixPtr; pixPtr = (unsigned int*)g_ogm.outputBuffer; //TODO: use one yuv->rgb funktion for the hole frame (the big amout of stack movement(yuv->rgb calls) couldn't be good ;) ) for(j=0;j<g_ogm.th_info.height;++j) { for(i=0;i<g_ogm.th_info.width;++i) { #if 1 // simple grayscale-output ^^ pixelPtr[0] = pixelPtr[1] = pixelPtr[2] = g_ogm.th_yuvbuffer.y[i+j*g_ogm.th_yuvbuffer.y_stride]; pixelPtr+=4; #else // using RoQ yuv->rgb code *pixPtr++ = yuv_to_rgb24( g_ogm.th_yuvbuffer.y[(i>>yWShift)+(j>>yHShift)*g_ogm.th_yuvbuffer.y_stride], g_ogm.th_yuvbuffer.u[(i>>uvWShift)+(j>>uvHShift)*g_ogm.th_yuvbuffer.uv_stride], g_ogm.th_yuvbuffer.v[(i>>uvWShift)+(j>>uvHShift)*g_ogm.th_yuvbuffer.uv_stride]); #endif } } */ r = 1; g_ogm.VFrameCount=th_frame; } } } return r; }