static int noop_test_encode () { th_info ti; th_enc_ctx *te; INFO ("+ Initializing th_info struct"); th_info_init (&ti); INFO ("+ Testing encoder context with empty th_info"); te = th_encode_alloc(&ti); if (te != NULL) FAIL("td_encode_alloc accepted an unconfigured th_info"); INFO ("+ Setting 16x16 image size"); ti.frame_width = 16; ti.frame_height = 16; INFO ("+ Allocating encoder context"); te = th_encode_alloc(&ti); if (te == NULL) FAIL("td_encode_alloc returned a null pointer"); INFO ("+ Clearing th_info struct"); th_info_clear (&ti); INFO ("+ Freeing encoder context"); th_encode_free(te); return 0; }
bool TheoraDecoder::initCodec() { th_comment_init(&mTheoraComment); th_info_init(&mTheoraInfo); return true; }
/***************************************************************************** * OpenDecoder: probe the decoder and return score *****************************************************************************/ static int OpenDecoder( vlc_object_t *p_this ) { decoder_t *p_dec = (decoder_t*)p_this; decoder_sys_t *p_sys; if( p_dec->fmt_in.i_codec != VLC_CODEC_THEORA ) { return VLC_EGENERIC; } /* Allocate the memory needed to store the decoder's structure */ if( ( p_dec->p_sys = p_sys = malloc(sizeof(*p_sys)) ) == NULL ) return VLC_ENOMEM; p_dec->p_sys->b_packetizer = false; p_sys->b_has_headers = false; p_sys->i_pts = VLC_TS_INVALID; p_sys->b_decoded_first_keyframe = false; p_sys->tcx = NULL; /* Set output properties */ p_dec->fmt_out.i_cat = VIDEO_ES; p_dec->fmt_out.i_codec = VLC_CODEC_I420; /* Set callbacks */ p_dec->pf_decode_video = (picture_t *(*)(decoder_t *, block_t **)) DecodeBlock; p_dec->pf_packetize = (block_t *(*)(decoder_t *, block_t **)) DecodeBlock; /* Init supporting Theora structures needed in header parsing */ th_comment_init( &p_sys->tc ); th_info_init( &p_sys->ti ); return VLC_SUCCESS; }
TheoraVideoStream::TheoraVideoStream(love::filesystem::File *file) : demuxer(file) , headerParsed(false) , decoder(nullptr) , frameReady(false) , lastFrame(0) , nextFrame(0) { if (demuxer.findStream() != OggDemuxer::TYPE_THEORA) throw love::Exception("Invalid video file, video is not theora"); th_info_init(&videoInfo); frontBuffer = new Frame(); backBuffer = new Frame(); try { parseHeader(); } catch (love::Exception &ex) { delete backBuffer; delete frontBuffer; th_info_clear(&videoInfo); throw ex; } frameSync.set(new DeltaSync(), Acquire::NORETAIN); }
static void * create_theora() { theora_t * ret; ret = calloc(1, sizeof(*ret)); th_info_init(&ret->ti); return ret; }
IoTheoraInfo *IoTheoraInfo_rawClone(IoTheoraInfo *proto) { IoObject *self = IoObject_rawClonePrimitive(proto); th_info* data = calloc(1, sizeof(th_info)); th_info_init(data); IoObject_setDataPointer_(self, data); return self; }
/* * Theora beginning of stream */ nsresult MediaRecorder::SetupTheoraBOS() { int i; nsresult rv; PRUint32 wr; ogg_uint32_t keyframe; if (ogg_stream_init(&vState->os, rand())) { PR_LOG(log, PR_LOG_NOTICE, ("Failed ogg_stream_init\n")); return NS_ERROR_FAILURE; } th_info_init(&vState->ti); /* Must be multiples of 16 */ vState->ti.frame_width = (params->width + 15) & ~0xF; vState->ti.frame_height = (params->height + 15) & ~0xF; vState->ti.pic_width = params->width; vState->ti.pic_height = params->height; vState->ti.pic_x = (vState->ti.frame_width - params->width) >> 1 & ~1; vState->ti.pic_y = (vState->ti.frame_height - params->height) >> 1 & ~1; vState->ti.fps_numerator = params->fps_n; vState->ti.fps_denominator = params->fps_d; /* Are these the right values? */ keyframe = 64 - 1; for (i = 0; keyframe; i++) keyframe >>= 1; vState->ti.quality = (int)(params->qual * 100); vState->ti.colorspace = TH_CS_ITU_REC_470M; vState->ti.pixel_fmt = TH_PF_420; vState->ti.keyframe_granule_shift = i; vState->th = th_encode_alloc(&vState->ti); th_info_clear(&vState->ti); /* Header init */ th_comment_init(&vState->tc); th_comment_add_tag(&vState->tc, (char *)"ENCODER", (char *)"rainbow"); if (th_encode_flushheader( vState->th, &vState->tc, &vState->op) <= 0) { PR_LOG(log, PR_LOG_NOTICE, ("Internal Theora library error\n")); return NS_ERROR_FAILURE; } th_comment_clear(&vState->tc); ogg_stream_packetin(&vState->os, &vState->op); if (ogg_stream_pageout(&vState->os, &vState->og) != 1) { PR_LOG(log, PR_LOG_NOTICE, ("Internal Ogg library error\n")); return NS_ERROR_FAILURE; } rv = WriteData(vState->og.header, vState->og.header_len, &wr); rv = WriteData(vState->og.body, vState->og.body_len, &wr); return NS_OK; }
TheoraEnc* theoraenc_new (void) { TheoraEnc* enc = malloc (sizeof (TheoraEnc)); if (enc == NULL) { printf ("ERROR: couldn't allocate encoder in theoraenc_new\n"); } enc->info = malloc (sizeof (th_info)); enc->comment = malloc (sizeof (th_comment)); if (enc->info && enc->comment) { th_info_init (enc->info); th_comment_init (enc->comment); } else { printf ("ERROR: couldn't alloc info/comment in theoraenc_new\n"); free (enc); return NULL; } /* hardcodes based on the example gstreamer v4l2 -> theora pipeline settings */ enc->info->frame_width = enc_frame_width; enc->info->frame_height = enc_frame_height; enc->info->pic_width = enc_pic_width; enc->info->pic_height = enc_pic_height; enc->info->fps_numerator = enc_fps_numerator; enc->info->fps_denominator = enc_fps_denominator; enc->info->quality = enc_quality; enc->info->target_bitrate = enc_target_bitrate; enc->info->keyframe_granule_shift = enc_keyframe_granule_shift; /* stuff that was already hardcoded in gstreamer's theora encoder */ enc->info->aspect_numerator = 0; enc->info->aspect_denominator = 0; enc->info->pixel_fmt = TH_PF_420; enc->info->colorspace = TH_CS_UNSPECIFIED; enc->ctx = th_encode_alloc (enc->info); if (enc->ctx == NULL) { printf ("Couldn't make a theora context in theoraenc_new.\n"); printf ("The most likely cause is specifying illegal theora encoder settings.\n"); printf ("Check the libtheora th_info documentation.\n"); free (enc); return NULL; } enc->postconv_buffer = calloc (PCONV_BUFFER_TOTAL_SIZE, (sizeof (unsigned char))); if (enc->postconv_buffer == NULL) { printf ("ERROR: couldn't alloc reserve buffer in theoraenc_new\n"); free (enc); return NULL; } return enc; }
TheoraState::TheoraState(ogg_page* aBosPage) : OggCodecState(aBosPage, true), mSetup(0), mCtx(0), mPixelAspectRatio(0) { MOZ_COUNT_CTOR(TheoraState); th_info_init(&mInfo); th_comment_init(&mComment); }
static gboolean theora_enc_set_format (GstVideoEncoder * benc, GstVideoCodecState * state) { GstTheoraEnc *enc = GST_THEORA_ENC (benc); GstVideoInfo *info = &state->info; enc->width = GST_VIDEO_INFO_WIDTH (info); enc->height = GST_VIDEO_INFO_HEIGHT (info); th_info_clear (&enc->info); th_info_init (&enc->info); /* Theora has a divisible-by-sixteen restriction for the encoded video size but * we can define a picture area using pic_width/pic_height */ enc->info.frame_width = GST_ROUND_UP_16 (enc->width); enc->info.frame_height = GST_ROUND_UP_16 (enc->height); enc->info.pic_width = enc->width; enc->info.pic_height = enc->height; switch (GST_VIDEO_INFO_FORMAT (info)) { case GST_VIDEO_FORMAT_I420: enc->info.pixel_fmt = TH_PF_420; break; case GST_VIDEO_FORMAT_Y42B: enc->info.pixel_fmt = TH_PF_422; break; case GST_VIDEO_FORMAT_Y444: enc->info.pixel_fmt = TH_PF_444; break; default: g_assert_not_reached (); } enc->info.fps_numerator = enc->fps_n = GST_VIDEO_INFO_FPS_N (info); enc->info.fps_denominator = enc->fps_d = GST_VIDEO_INFO_FPS_D (info); enc->info.aspect_numerator = GST_VIDEO_INFO_PAR_N (info); enc->info.aspect_denominator = GST_VIDEO_INFO_PAR_D (info); enc->info.colorspace = TH_CS_UNSPECIFIED; /* Save input state */ if (enc->input_state) gst_video_codec_state_unref (enc->input_state); enc->input_state = gst_video_codec_state_ref (state); /* as done in theora */ enc->info.keyframe_granule_shift = _ilog (enc->keyframe_force - 1); GST_DEBUG_OBJECT (enc, "keyframe_frequency_force is %d, granule shift is %d", enc->keyframe_force, enc->info.keyframe_granule_shift); theora_enc_reset (enc); enc->initialised = TRUE; return TRUE; }
nsTheoraState::nsTheoraState(ogg_page* aBosPage) : nsOggCodecState(aBosPage), mSetup(0), mCtx(0), mFrameDuration(0), mPixelAspectRatio(0) { MOZ_COUNT_CTOR(nsTheoraState); th_info_init(&mInfo); th_comment_init(&mComment); }
static int noop_test_info () { th_info ti; INFO ("+ Initializing th_info struct"); th_info_init (&ti); INFO ("+ Clearing empty th_info struct"); th_info_clear (&ti); return 0; }
/***************************************************************************** * OpenEncoder: probe the encoder and return score *****************************************************************************/ static int OpenEncoder( vlc_object_t *p_this ) { encoder_t *p_enc = (encoder_t *)p_this; encoder_sys_t *p_sys; int i_quality; int t_flags; int max_enc_level = 0; int keyframe_freq_force = 64; ogg_packet header; int status; if( p_enc->fmt_out.i_codec != VLC_CODEC_THEORA && !p_enc->obj.force ) { return VLC_EGENERIC; } /* Allocate the memory needed to store the encoder's structure */ if( ( p_sys = malloc(sizeof(encoder_sys_t)) ) == NULL ) return VLC_ENOMEM; p_enc->p_sys = p_sys; p_enc->pf_encode_video = Encode; p_enc->fmt_in.i_codec = VLC_CODEC_I420; p_enc->fmt_out.i_codec = VLC_CODEC_THEORA; config_ChainParse( p_enc, ENC_CFG_PREFIX, ppsz_enc_options, p_enc->p_cfg ); i_quality = var_GetInteger( p_enc, ENC_CFG_PREFIX "quality" ); if( i_quality > 10 ) i_quality = 10; if( i_quality < 0 ) i_quality = 0; th_info_init( &p_sys->ti ); p_sys->ti.frame_width = p_enc->fmt_in.video.i_visible_width; p_sys->ti.frame_height = p_enc->fmt_in.video.i_visible_height; if( p_sys->ti.frame_width % 16 || p_sys->ti.frame_height % 16 ) { /* Pictures from the transcoder should always have a pitch * which is a multiple of 16 */ p_sys->ti.frame_width = (p_sys->ti.frame_width + 15) >> 4 << 4; p_sys->ti.frame_height = (p_sys->ti.frame_height + 15) >> 4 << 4; msg_Dbg( p_enc, "padding video from %dx%d to %dx%d", p_enc->fmt_in.video.i_visible_width, p_enc->fmt_in.video.i_visible_height, p_sys->ti.frame_width, p_sys->ti.frame_height ); }
static char * theora_enc_get_supported_formats (void) { th_enc_ctx *encoder; th_info info; struct { th_pixel_fmt pixelformat; const char *fourcc; } formats[] = { { TH_PF_420, "I420" }, { TH_PF_422, "Y42B" }, { TH_PF_444, "Y444" } }; GString *string = NULL; guint i; th_info_init (&info); info.frame_width = 16; info.frame_height = 16; info.fps_numerator = 25; info.fps_denominator = 1; for (i = 0; i < G_N_ELEMENTS (formats); i++) { info.pixel_fmt = formats[i].pixelformat; encoder = th_encode_alloc (&info); if (encoder == NULL) continue; GST_LOG ("format %s is supported", formats[i].fourcc); th_encode_free (encoder); if (string == NULL) { string = g_string_new (formats[i].fourcc); } else { g_string_append (string, ", "); g_string_append (string, formats[i].fourcc); } } th_info_clear (&info); return string == NULL ? NULL : g_string_free (string, FALSE); }
static GstStateChangeReturn theora_parse_change_state (GstElement * element, GstStateChange transition) { GstTheoraParse *parse = GST_THEORA_PARSE (element); GstStateChangeReturn ret; gint i; switch (transition) { case GST_STATE_CHANGE_READY_TO_PAUSED: th_info_init (&parse->info); th_comment_init (&parse->comment); parse->send_streamheader = TRUE; parse->buffer_queue = g_queue_new (); parse->event_queue = g_queue_new (); parse->prev_keyframe = -1; parse->prev_frame = -1; parse->granule_offset = 0; break; default: break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: th_info_clear (&parse->info); th_comment_clear (&parse->comment); theora_parse_clear_queue (parse); g_queue_free (parse->buffer_queue); g_queue_free (parse->event_queue); parse->buffer_queue = NULL; for (i = 0; i < 3; i++) { if (parse->streamheader[i]) { gst_buffer_unref (parse->streamheader[i]); parse->streamheader[i] = NULL; } } parse->streamheader_received = FALSE; break; default: break; } return ret; }
krad_theora_decoder_t *krad_theora_decoder_create(unsigned char *header1, int header1len, unsigned char *header2, int header2len, unsigned char *header3, int header3len) { krad_theora_decoder_t *krad_theora; krad_theora = calloc(1, sizeof(krad_theora_decoder_t)); krad_theora->granulepos = -1; th_comment_init(&krad_theora->comment); th_info_init(&krad_theora->info); krad_theora->packet.packet = header1; krad_theora->packet.bytes = header1len; krad_theora->packet.b_o_s = 1; krad_theora->packet.packetno = 1; th_decode_headerin(&krad_theora->info, &krad_theora->comment, &krad_theora->setup_info, &krad_theora->packet); //printf("x is %d len is %d\n", x, header1len); krad_theora->packet.packet = header2; krad_theora->packet.bytes = header2len; krad_theora->packet.b_o_s = 0; krad_theora->packet.packetno = 2; th_decode_headerin(&krad_theora->info, &krad_theora->comment, &krad_theora->setup_info, &krad_theora->packet); //printf("x is %d len is %d\n", x, header2len); krad_theora->packet.packet = header3; krad_theora->packet.bytes = header3len; krad_theora->packet.packetno = 3; th_decode_headerin(&krad_theora->info, &krad_theora->comment, &krad_theora->setup_info, &krad_theora->packet); printf("Theora %dx%d %.02f fps video\n Encoded frame content is %dx%d with %dx%d offset\n", krad_theora->info.frame_width, krad_theora->info.frame_height, (double)krad_theora->info.fps_numerator/krad_theora->info.fps_denominator, krad_theora->info.pic_width, krad_theora->info.pic_height, krad_theora->info.pic_x, krad_theora->info.pic_y); krad_theora->decoder = th_decode_alloc(&krad_theora->info, krad_theora->setup_info); th_setup_free(krad_theora->setup_info); return krad_theora; }
static gboolean theora_enc_start (GstVideoEncoder * benc) { GstTheoraEnc *enc; GST_DEBUG_OBJECT (benc, "start: init theora"); enc = GST_THEORA_ENC (benc); th_info_init (&enc->info); th_comment_init (&enc->comment); enc->packetno = 0; if (enc->multipass_mode >= MULTIPASS_MODE_FIRST_PASS) { GError *err = NULL; if (!enc->multipass_cache_file) { GST_ELEMENT_ERROR (enc, LIBRARY, SETTINGS, (NULL), (NULL)); return FALSE; } enc->multipass_cache_fd = g_io_channel_new_file (enc->multipass_cache_file, (enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS ? "w" : "r"), &err); if (enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS) enc->multipass_cache_adapter = gst_adapter_new (); if (!enc->multipass_cache_fd) { GST_ELEMENT_ERROR (enc, RESOURCE, OPEN_READ, (NULL), ("Failed to open multipass cache file: %s", err->message)); g_error_free (err); return FALSE; } g_io_channel_set_encoding (enc->multipass_cache_fd, NULL, NULL); } return TRUE; }
/* Generate a dummy encoder context for use in th_encode_ctl queries */ th_enc_ctx *dummy_encode_ctx(void) { th_enc_ctx *ctx; th_info info; /* set the minimal video parameters */ th_info_init(&info); info.frame_width=320; info.frame_height=240; info.fps_numerator=1; info.fps_denominator=1; /* allocate and initialize a context object */ ctx = th_encode_alloc(&info); if (ctx == NULL) { fprintf(stderr, "Error allocating encoder context.\n"); } /* clear the info struct */ th_info_clear(&info); return ctx; }
IoTheoraInfo *IoTheoraInfo_proto(void *state) { IoTheoraInfo *self = IoObject_new(state); IoObject_tag_(self, IoTheoraInfo_newTag(state)); th_info* data = calloc(1, sizeof(th_info)); th_info_init(data); IoObject_setDataPointer_(self, data); IoState_registerProtoWithFunc_(state, self, IoTheoraInfo_proto); { IoMethodTable methodTable[] = { {"frameWidth", IoTheoraInfo_frameWidth}, {"frameHeight", IoTheoraInfo_frameHeight}, {"frameRate", IoTheoraInfo_frameRate}, {NULL, NULL}, }; IoObject_addMethodTable_(self, methodTable); } return self; }
/* Generate a dummy encoder context for use in th_encode_ctl queries Release with th_encode_free() This and the next routine from theora/examples/libtheora_info.c */ static th_enc_ctx * dummy_encode_ctx (void) { th_enc_ctx *ctx; th_info info; /* set the minimal video parameters */ th_info_init (&info); info.frame_width = 320; info.frame_height = 240; info.fps_numerator = 1; info.fps_denominator = 1; /* allocate and initialize a context object */ ctx = th_encode_alloc (&info); if (!ctx) GST_WARNING ("Failed to allocate dummy encoder context."); /* clear the info struct */ th_info_clear (&info); return ctx; }
void gobee_theora_resize(int w, int h, int _stride, int sock, struct sockaddr *addr, int addrlen) { time_t stamp = time(NULL); th_info_init(&tinfo); th_comment_init(&tcmnt); tinfo.frame_width = w; tinfo.frame_height = h; tinfo.pic_width = w; tinfo.pic_height = h; tinfo.pic_y = 0; tinfo.pic_x = 0; tinfo.fps_numerator = 30; tinfo.fps_denominator = 1; tinfo.aspect_denominator = 1; tinfo.aspect_numerator = 1; tinfo.target_bitrate = 200000; tinfo.quality = 12; tinfo.colorspace = TH_CS_ITU_REC_470BG; //TH_CS_UNSPECIFIED; tinfo.pixel_fmt = TH_PF_420; tinfo.keyframe_granule_shift = 100; tcmnt.vendor = "qqq"; // recreate encoder if (tctx) th_encode_free(tctx); tctx = th_encode_alloc(&tinfo); __gobee_yuv_resize(&s_ycbcr, w, h); printf("sending...\n"); __gobee_theora_send_headers(sock, addr, addrlen, stamp); printf("sent...\n"); }
static int OpenCommon( vlc_object_t *p_this, bool b_packetizer ) { decoder_t *p_dec = (decoder_t*)p_this; decoder_sys_t *p_sys; if( p_dec->fmt_in.i_codec != VLC_CODEC_THEORA ) { return VLC_EGENERIC; } /* Allocate the memory needed to store the decoder's structure */ if( ( p_dec->p_sys = p_sys = malloc(sizeof(*p_sys)) ) == NULL ) return VLC_ENOMEM; p_sys->b_packetizer = b_packetizer; p_sys->b_has_headers = false; p_sys->i_pts = VLC_TICK_INVALID; p_sys->b_decoded_first_keyframe = false; p_sys->tcx = NULL; if( b_packetizer ) { p_dec->fmt_out.i_codec = VLC_CODEC_THEORA; p_dec->pf_packetize = Packetize; } else { p_dec->fmt_out.i_codec = VLC_CODEC_I420; p_dec->pf_decode = DecodeVideo; } p_dec->pf_flush = Flush; /* Init supporting Theora structures needed in header parsing */ th_comment_init( &p_sys->tc ); th_info_init( &p_sys->ti ); return VLC_SUCCESS; }
bool CHolly_Theora_Video::Start() { m_bFrameWaiting = false; th_info thInfo; th_info_init( &thInfo ); thInfo.frame_width = Width(); thInfo.frame_height = Height(); thInfo.pic_width = Width(); thInfo.pic_height = Height(); thInfo.pic_x = 0; thInfo.pic_y = 0; thInfo.colorspace = TH_CS_ITU_REC_470BG; thInfo.pixel_fmt = TH_PF_420; // TH_PF_444 thInfo.target_bitrate = BitRate() * 1024; thInfo.quality = 42; thInfo.keyframe_granule_shift = 6; // default value thInfo.fps_numerator = FPS(); thInfo.fps_denominator = 1; thInfo.aspect_numerator = 1; thInfo.aspect_denominator = 1; m_Encoder = th_encode_alloc( &thInfo ); if ( !m_Encoder ) { return false; } th_info_clear( &thInfo ); SetupFrame(); WriteHeader(); return true; }
static int noop_test_decode () { th_info ti; th_dec_ctx *td; INFO ("+ Testing decoder context with null info and setup"); td = th_decode_alloc(NULL, NULL); if (td != NULL) FAIL("td_decode_alloc accepted null info pointers"); INFO ("+ Initializing th_info struct"); th_info_init (&ti); INFO ("+ Testing decoder context with empty info and null setup"); td = th_decode_alloc(&ti, NULL); if (td != NULL) FAIL("td_decode_alloc accepted null info pointers"); INFO ("+ Clearing th_info struct"); th_info_clear (&ti); return 0; }
krad_theora_decoder_t * krad_theora_decoder_create (krad_codec_header_t *header) { krad_theora_decoder_t *krad_theora; krad_theora = calloc(1, sizeof(krad_theora_decoder_t)); krad_theora->granulepos = -1; th_comment_init(&krad_theora->comment); th_info_init(&krad_theora->info); /* krad_theora->packet.packet = header->header[0]; krad_theora->packet.bytes = header->header_size[0]; krad_theora->packet.b_o_s = 1; krad_theora->packet.packetno = 1; th_decode_headerin (&krad_theora->info, &krad_theora->comment, &krad_theora->setup_info, &krad_theora->packet); krad_theora->packet.packet = header->header[1]; krad_theora->packet.bytes = header->header_size[1]; krad_theora->packet.b_o_s = 0; krad_theora->packet.packetno = 2; th_decode_headerin (&krad_theora->info, &krad_theora->comment, &krad_theora->setup_info, &krad_theora->packet); krad_theora->packet.packet = header->header[2]; krad_theora->packet.bytes = header->header_size[2]; krad_theora->packet.packetno = 3; th_decode_headerin (&krad_theora->info, &krad_theora->comment, &krad_theora->setup_info, &krad_theora->packet); krad_theora->color_depth = PIX_FMT_YUV420P; if (krad_theora->info.pixel_fmt == TH_PF_422) { krad_theora->color_depth = PIX_FMT_YUV422P; printk ("Theora color depth 422"); } if (krad_theora->info.pixel_fmt == TH_PF_444) { krad_theora->color_depth = PIX_FMT_YUV444P; printk ("Theora color depth 444"); } */ printk ("Theora %dx%d %.02f fps video\n Encoded frame content is %dx%d with %dx%d offset", krad_theora->info.frame_width, krad_theora->info.frame_height, (double)krad_theora->info.fps_numerator/krad_theora->info.fps_denominator, krad_theora->info.pic_width, krad_theora->info.pic_height, krad_theora->info.pic_x, krad_theora->info.pic_y); krad_theora->offset_y = krad_theora->info.pic_y; krad_theora->offset_x = krad_theora->info.pic_x; krad_theora->width = krad_theora->info.pic_width; krad_theora->height = krad_theora->info.pic_height; krad_theora->decoder = th_decode_alloc (&krad_theora->info, krad_theora->setup_info); th_setup_free(krad_theora->setup_info); return krad_theora; }
void VideoStreamPlaybackTheora::set_file(const String &p_file) { ERR_FAIL_COND(playing); ogg_packet op; th_setup_info *ts = NULL; file_name = p_file; if (file) { memdelete(file); } file = FileAccess::open(p_file, FileAccess::READ); ERR_FAIL_COND(!file); #ifdef THEORA_USE_THREAD_STREAMING thread_exit = false; thread_eof = false; //pre-fill buffer int to_read = ring_buffer.space_left(); int read = file->get_buffer(read_buffer.ptr(), to_read); ring_buffer.write(read_buffer.ptr(), read); thread = Thread::create(_streaming_thread, this); #endif ogg_sync_init(&oy); /* init supporting Vorbis structures needed in header parsing */ vorbis_info_init(&vi); vorbis_comment_init(&vc); /* init supporting Theora structures needed in header parsing */ th_comment_init(&tc); th_info_init(&ti); theora_eos = false; vorbis_eos = false; /* Ogg file open; parse the headers */ /* Only interested in Vorbis/Theora streams */ int stateflag = 0; int audio_track_skip = audio_track; while (!stateflag) { int ret = buffer_data(); if (ret == 0) break; while (ogg_sync_pageout(&oy, &og) > 0) { ogg_stream_state test; /* is this a mandated initial header? If not, stop parsing */ if (!ogg_page_bos(&og)) { /* don't leak the page; get it into the appropriate stream */ queue_page(&og); stateflag = 1; break; } ogg_stream_init(&test, ogg_page_serialno(&og)); ogg_stream_pagein(&test, &og); ogg_stream_packetout(&test, &op); /* identify the codec: try theora */ if (!theora_p && th_decode_headerin(&ti, &tc, &ts, &op) >= 0) { /* it is theora */ copymem(&to, &test, sizeof(test)); theora_p = 1; } else if (!vorbis_p && vorbis_synthesis_headerin(&vi, &vc, &op) >= 0) { /* it is vorbis */ if (audio_track_skip) { vorbis_info_clear(&vi); vorbis_comment_clear(&vc); ogg_stream_clear(&test); vorbis_info_init(&vi); vorbis_comment_init(&vc); audio_track_skip--; } else { copymem(&vo, &test, sizeof(test)); vorbis_p = 1; } } else { /* whatever it is, we don't care about it */ ogg_stream_clear(&test); } } /* fall through to non-bos page parsing */ } /* we're expecting more header packets. */ while ((theora_p && theora_p < 3) || (vorbis_p && vorbis_p < 3)) { int ret; /* look for further theora headers */ while (theora_p && (theora_p < 3) && (ret = ogg_stream_packetout(&to, &op))) { if (ret < 0) { fprintf(stderr, "Error parsing Theora stream headers; " "corrupt stream?\n"); clear(); return; } if (!th_decode_headerin(&ti, &tc, &ts, &op)) { fprintf(stderr, "Error parsing Theora stream headers; " "corrupt stream?\n"); clear(); return; } theora_p++; } /* look for more vorbis header packets */ while (vorbis_p && (vorbis_p < 3) && (ret = ogg_stream_packetout(&vo, &op))) { if (ret < 0) { fprintf(stderr, "Error parsing Vorbis stream headers; corrupt stream?\n"); clear(); return; } ret = vorbis_synthesis_headerin(&vi, &vc, &op); if (ret) { fprintf(stderr, "Error parsing Vorbis stream headers; corrupt stream?\n"); clear(); return; } vorbis_p++; if (vorbis_p == 3) break; } /* The header pages/packets will arrive before anything else we care about, or the stream is not obeying spec */ if (ogg_sync_pageout(&oy, &og) > 0) { queue_page(&og); /* demux into the appropriate stream */ } else { int ret = buffer_data(); /* someone needs more data */ if (ret == 0) { fprintf(stderr, "End of file while searching for codec headers.\n"); clear(); return; } } } /* and now we have it all. initialize decoders */ if (theora_p) { td = th_decode_alloc(&ti, ts); printf("Ogg logical stream %lx is Theora %dx%d %.02f fps", to.serialno, ti.pic_width, ti.pic_height, (double)ti.fps_numerator / ti.fps_denominator); px_fmt = ti.pixel_fmt; switch (ti.pixel_fmt) { case TH_PF_420: printf(" 4:2:0 video\n"); break; case TH_PF_422: printf(" 4:2:2 video\n"); break; case TH_PF_444: printf(" 4:4:4 video\n"); break; case TH_PF_RSVD: default: printf(" video\n (UNKNOWN Chroma sampling!)\n"); break; } if (ti.pic_width != ti.frame_width || ti.pic_height != ti.frame_height) printf(" Frame content is %dx%d with offset (%d,%d).\n", ti.frame_width, ti.frame_height, ti.pic_x, ti.pic_y); th_decode_ctl(td, TH_DECCTL_GET_PPLEVEL_MAX, &pp_level_max, sizeof(pp_level_max)); pp_level = 0; th_decode_ctl(td, TH_DECCTL_SET_PPLEVEL, &pp_level, sizeof(pp_level)); pp_inc = 0; int w; int h; w = (ti.pic_x + ti.frame_width + 1 & ~1) - (ti.pic_x & ~1); h = (ti.pic_y + ti.frame_height + 1 & ~1) - (ti.pic_y & ~1); size.x = w; size.y = h; texture->create(w, h, Image::FORMAT_RGBA8, Texture::FLAG_FILTER | Texture::FLAG_VIDEO_SURFACE); } else { /* tear down the partial theora setup */ th_info_clear(&ti); th_comment_clear(&tc); } th_setup_free(ts); if (vorbis_p) { vorbis_synthesis_init(&vd, &vi); vorbis_block_init(&vd, &vb); fprintf(stderr, "Ogg logical stream %lx is Vorbis %d channel %ld Hz audio.\n", vo.serialno, vi.channels, vi.rate); //_setup(vi.channels, vi.rate); } else { /* tear down the partial vorbis setup */ vorbis_info_clear(&vi); vorbis_comment_clear(&vc); } playing = false; buffering = true; time = 0; audio_frames_wrote = 0; };
krad_theora_encoder_t *krad_theora_encoder_create (int width, int height, int fps_numerator, int fps_denominator, int color_depth, int quality) { krad_theora_encoder_t *krad_theora; krad_theora = calloc (1, sizeof(krad_theora_encoder_t)); krad_theora->width = width; krad_theora->height = height; krad_theora->quality = quality; krad_theora->color_depth = color_depth; th_info_init (&krad_theora->info); th_comment_init (&krad_theora->comment); krad_theora->info.frame_width = krad_theora->width; if (krad_theora->width % 16) { krad_theora->info.frame_width += 16 - (krad_theora->width % 16); } krad_theora->info.frame_height = krad_theora->height; if (krad_theora->height % 16) { krad_theora->info.frame_height += 16 - (krad_theora->height % 16); } krad_theora->info.pic_width = krad_theora->width; krad_theora->info.pic_height = krad_theora->height; krad_theora->info.pic_x = 0; krad_theora->info.pic_y = 0; krad_theora->info.aspect_denominator = 1; krad_theora->info.aspect_numerator = 1; krad_theora->info.target_bitrate = 0; krad_theora->info.quality = krad_theora->quality; if (krad_theora->color_depth == PIX_FMT_YUV420P) { krad_theora->info.pixel_fmt = TH_PF_420; } if (krad_theora->color_depth == PIX_FMT_YUV422P) { krad_theora->info.pixel_fmt = TH_PF_422; } if (krad_theora->color_depth == PIX_FMT_YUV444P) { krad_theora->info.pixel_fmt = TH_PF_444; } krad_theora->keyframe_shift = krad_theora->info.keyframe_granule_shift; printk ("Loading Theora encoder version %s", th_version_string()); printk ("Theora keyframe shift %d", krad_theora->keyframe_shift); krad_theora->info.fps_numerator = fps_numerator; krad_theora->info.fps_denominator = fps_denominator; //krad_theora->keyframe_distance = 30; krad_theora->encoder = th_encode_alloc (&krad_theora->info); //th_encode_ctl (krad_theora->encoder, //TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE, // &krad_theora->keyframe_distance, sizeof(int)); //printk ("Theora keyframe max distance %u\n", // krad_theora->keyframe_distance); /* if (strstr(krad_system_cpu_type(), "x86") == NULL) { //FOR ARM Realtime th_encode_ctl (krad_theora->encoder, TH_ENCCTL_GET_SPLEVEL_MAX, &krad_theora->speed, sizeof(int)); printk ("Theora encoder speed: %d quality: %d", krad_theora->speed, krad_theora->quality); th_encode_ctl (krad_theora->encoder, TH_ENCCTL_SET_SPLEVEL, &krad_theora->speed, sizeof(int)); } else { //FOR x86 Realtime th_encode_ctl (krad_theora->encoder, TH_ENCCTL_GET_SPLEVEL_MAX, &krad_theora->speed, sizeof(int)); if ((krad_theora->width <= 1280) && (krad_theora->height <= 720)) { krad_theora->speed -= 1; } printk ("Theora encoder speed: %d quality: %d", krad_theora->speed, krad_theora->quality); th_encode_ctl (krad_theora->encoder, TH_ENCCTL_SET_SPLEVEL, &krad_theora->speed, sizeof(int)); } */ /* while (th_encode_flushheader ( krad_theora->encoder, &krad_theora->comment, &krad_theora->packet) > 0) { krad_theora->header_combined_size += krad_theora->packet.bytes; krad_theora->header[krad_theora->header_count] = malloc (krad_theora->packet.bytes); memcpy (krad_theora->header[krad_theora->header_count], krad_theora->packet.packet, krad_theora->packet.bytes); krad_theora->header_len[krad_theora->header_count] = krad_theora->packet.bytes; krad_theora->header_count++; //printk ("krad_theora_encoder_create th_encode_flushheader got // header packet %"PRIi64" which is %ld bytes\n", // krad_theora->packet.packetno, krad_theora->packet.bytes); } //printk ("krad_theora_encoder_create Got %d header packets\n", // krad_theora->header_count); krad_theora->header_combined = calloc (1, krad_theora->header_combined_size + 10); krad_theora->header_combined[0] = 0x02; krad_theora->header_combined_pos++; //printk ("main is %ld\n", vorbis->header_main.bytes); if (krad_theora->header_len[0] > 255) { failfast ("theora mainheader to long for code"); } krad_theora->demented = krad_theora->header_len[0]; krad_theora->header_combined[1] = (char)krad_theora->demented; krad_theora->header_combined_pos++; //printk ("comments is %ld\n", vorbis->header_comments.bytes); if (krad_theora->header_len[1] > 255) { failfast ("theora comments header to long for code"); } krad_theora->demented = krad_theora->header_len[1]; krad_theora->header_combined[2] = (char)krad_theora->demented; krad_theora->header_combined_pos++; krad_theora->header_combined_size += 3; memcpy (krad_theora->header_combined + krad_theora->header_combined_pos, krad_theora->header[0], krad_theora->header_len[0]); krad_theora->header_combined_pos += krad_theora->header_len[0]; //printf("main is %ld bytes headerpos is %d \n", //vorbis->header_main.bytes, vorbis->headerpos); memcpy (krad_theora->header_combined + krad_theora->header_combined_pos, krad_theora->header[1], krad_theora->header_len[1]); krad_theora->header_combined_pos += krad_theora->header_len[1]; //printf("comments is %ld bytes headerpos is %d \n", //vorbis->header_comments.bytes, vorbis->headerpos); memcpy (krad_theora->header_combined + krad_theora->header_combined_pos, krad_theora->header[2], krad_theora->header_len[2]); krad_theora->header_combined_pos += krad_theora->header_len[2]; krad_theora->krad_codec_header.codec = THEORA; krad_theora->krad_codec_header.header[0] = krad_theora->header[0]; krad_theora->krad_codec_header.header_size[0] = krad_theora->header_len[0]; krad_theora->krad_codec_header.header[1] = krad_theora->header[1]; krad_theora->krad_codec_header.header_size[1] = krad_theora->header_len[1]; krad_theora->krad_codec_header.header[2] = krad_theora->header[2]; krad_theora->krad_codec_header.header_size[2] = krad_theora->header_len[2]; krad_theora->krad_codec_header.header_combined = krad_theora->header_combined; krad_theora->krad_codec_header.header_combined_size = krad_theora->header_combined_size; krad_theora->krad_codec_header.header_count = 3; krad_theora->ycbcr[0].stride = krad_theora->info.frame_width; krad_theora->ycbcr[0].width = krad_theora->info.frame_width; krad_theora->ycbcr[0].height = krad_theora->info.frame_height; krad_theora->ycbcr[0].data = calloc(1, krad_theora->info.frame_width * krad_theora->info.frame_height); if (krad_theora->color_depth == PIX_FMT_YUV420P) { krad_theora->ycbcr[1].stride = krad_theora->info.frame_width / 2; krad_theora->ycbcr[1].width = krad_theora->info.frame_width / 2; krad_theora->ycbcr[1].height = krad_theora->info.frame_height / 2; krad_theora->ycbcr[2].stride = krad_theora->info.frame_width / 2; krad_theora->ycbcr[2].width = krad_theora->info.frame_width / 2; krad_theora->ycbcr[2].height = krad_theora->info.frame_height / 2; krad_theora->ycbcr[1].data = calloc(1, ((krad_theora->info.frame_width / 2) * (krad_theora->info.frame_height / 2))); krad_theora->ycbcr[2].data = calloc(1, ((krad_theora->info.frame_width / 2) * (krad_theora->info.frame_height / 2))); } if (krad_theora->color_depth == PIX_FMT_YUV422P) { krad_theora->ycbcr[1].stride = krad_theora->info.frame_width / 2; krad_theora->ycbcr[1].width = krad_theora->info.frame_width / 2; krad_theora->ycbcr[1].height = krad_theora->info.frame_height; krad_theora->ycbcr[2].stride = krad_theora->info.frame_width / 2; krad_theora->ycbcr[2].width = krad_theora->info.frame_width / 2; krad_theora->ycbcr[2].height = krad_theora->info.frame_height; krad_theora->ycbcr[1].data = calloc(1, ((krad_theora->info.frame_width / 2) * krad_theora->info.frame_height)); krad_theora->ycbcr[2].data = calloc(1, ((krad_theora->info.frame_width / 2) * krad_theora->info.frame_height)); } if (krad_theora->color_depth == PIX_FMT_YUV444P) { krad_theora->ycbcr[1].stride = krad_theora->info.frame_width; krad_theora->ycbcr[1].width = krad_theora->info.frame_width; krad_theora->ycbcr[1].height = krad_theora->info.frame_height; krad_theora->ycbcr[2].stride = krad_theora->info.frame_width; krad_theora->ycbcr[2].width = krad_theora->info.frame_width; krad_theora->ycbcr[2].height = krad_theora->info.frame_height; krad_theora->ycbcr[1].data = calloc(1, krad_theora->info.frame_width * krad_theora->info.frame_height); krad_theora->ycbcr[2].data = calloc(1, krad_theora->info.frame_width * krad_theora->info.frame_height); } */ return krad_theora; }
bool TheoraDecoder::loadStream(Common::SeekableReadStream *stream) { close(); _fileStream = stream; // start up Ogg stream synchronization layer ogg_sync_init(&_oggSync); // init supporting Vorbis structures needed in header parsing vorbis_info_init(&_vorbisInfo); vorbis_comment vorbisComment; vorbis_comment_init(&vorbisComment); // init supporting Theora structures needed in header parsing th_info theoraInfo; th_info_init(&theoraInfo); th_comment theoraComment; th_comment_init(&theoraComment); th_setup_info *theoraSetup = 0; uint theoraPackets = 0, vorbisPackets = 0; // Ogg file open; parse the headers // Only interested in Vorbis/Theora streams bool foundHeader = false; while (!foundHeader) { int ret = bufferData(); if (ret == 0) break; // FIXME: Shouldn't this error out? while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) { ogg_stream_state test; // is this a mandated initial header? If not, stop parsing if (!ogg_page_bos(&_oggPage)) { // don't leak the page; get it into the appropriate stream queuePage(&_oggPage); foundHeader = true; break; } ogg_stream_init(&test, ogg_page_serialno(&_oggPage)); ogg_stream_pagein(&test, &_oggPage); ogg_stream_packetout(&test, &_oggPacket); // identify the codec: try theora if (theoraPackets == 0 && th_decode_headerin(&theoraInfo, &theoraComment, &theoraSetup, &_oggPacket) >= 0) { // it is theora memcpy(&_theoraOut, &test, sizeof(test)); theoraPackets = 1; _hasVideo = true; } else if (vorbisPackets == 0 && vorbis_synthesis_headerin(&_vorbisInfo, &vorbisComment, &_oggPacket) >= 0) { // it is vorbis memcpy(&_vorbisOut, &test, sizeof(test)); vorbisPackets = 1; _hasAudio = true; } else { // whatever it is, we don't care about it ogg_stream_clear(&test); } } // fall through to non-bos page parsing } // we're expecting more header packets. while ((theoraPackets && theoraPackets < 3) || (vorbisPackets && vorbisPackets < 3)) { int ret; // look for further theora headers while (theoraPackets && (theoraPackets < 3) && (ret = ogg_stream_packetout(&_theoraOut, &_oggPacket))) { if (ret < 0) error("Error parsing Theora stream headers; corrupt stream?"); if (!th_decode_headerin(&theoraInfo, &theoraComment, &theoraSetup, &_oggPacket)) error("Error parsing Theora stream headers; corrupt stream?"); theoraPackets++; } // look for more vorbis header packets while (vorbisPackets && (vorbisPackets < 3) && (ret = ogg_stream_packetout(&_vorbisOut, &_oggPacket))) { if (ret < 0) error("Error parsing Vorbis stream headers; corrupt stream?"); if (vorbis_synthesis_headerin(&_vorbisInfo, &vorbisComment, &_oggPacket)) error("Error parsing Vorbis stream headers; corrupt stream?"); vorbisPackets++; if (vorbisPackets == 3) break; } // The header pages/packets will arrive before anything else we // care about, or the stream is not obeying spec if (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) { queuePage(&_oggPage); // demux into the appropriate stream } else { ret = bufferData(); // someone needs more data if (ret == 0) error("End of file while searching for codec headers."); } } // And now we have it all. Initialize decoders next if (_hasVideo) { _videoTrack = new TheoraVideoTrack(getDefaultHighColorFormat(), theoraInfo, theoraSetup); addTrack(_videoTrack); } th_info_clear(&theoraInfo); th_comment_clear(&theoraComment); th_setup_free(theoraSetup); if (_hasAudio) { _audioTrack = new VorbisAudioTrack(_soundType, _vorbisInfo); // Get enough audio data to start us off while (!_audioTrack->hasAudio()) { // Queue more data bufferData(); while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) queuePage(&_oggPage); queueAudio(); } addTrack(_audioTrack); } vorbis_comment_clear(&vorbisComment); return true; }
void writeTheora(std::vector<std::vector<uint8_t>> vidframes, std::string writeTo, uint16_t vidWidth, uint16_t vidHeight) { // get paddings to nearest multiple of 0x10 uint32_t padW = 16 - vidWidth % 16; uint32_t padH = 16 - vidHeight % 16; uint32_t frmWidth = vidWidth + padW; uint32_t frmHeight = vidHeight + padH; // initialize theora stream th_info vidinfo; th_info_init(&vidinfo); vidinfo.frame_width = frmWidth; vidinfo.frame_height = frmHeight; vidinfo.pic_width = vidWidth; vidinfo.pic_height = vidHeight; vidinfo.pic_x = 0; vidinfo.pic_y = 0; vidinfo.colorspace = TH_CS_ITU_REC_470M; // what our RGB->YCbCr function operates on vidinfo.pixel_fmt = TH_PF_444; // we want the bestest video possible, so no decimation vidinfo.target_bitrate = 0; // prefer VBR with quality level... vidinfo.quality = 63; // ...which we want as high as possible (since we aren't using photographic frames, lossy compression ruins things) vidinfo.fps_numerator = 15; // framerate is 15 fps vidinfo.fps_denominator = 1; // initialize theora encoding context th_enc_ctx * videnc = th_encode_alloc(&vidinfo); // initialize theora comment th_comment vidcomment; th_comment_init(&vidcomment); // initialize ogg container ogg_stream_state vidcont; // serial number chosen by fair dice roll if (ogg_stream_init(&vidcont, 42)) { // returned -1, thus failed std::cerr << "Failed to initialize ogg container :(\n"; throw 42; } // get generic ogg packet & page holders ogg_packet vidpacket; ogg_page vidpage; // generic YCbCr frame, and initial data const int Y = 0; const int Cb = 1; const int Cr = 2; // clarity bonuses th_ycbcr_buffer rawdata; for (auto & i : rawdata) { i.width = i.stride = frmWidth; i.height = frmHeight; i.data = new unsigned char [frmWidth * frmHeight]; } // open file for writing std::ofstream vidfile; // because god forbid this thing supports an unsigned char unit vidfile.open(writeTo, std::ios::binary); // factor out the ogg page writing process a bit auto writePage = [&](){ vidfile.write((char*)vidpage.header, vidpage.header_len); if (!vidfile) { std::cerr << "An error occured in writing Ogg page header to file. Exiting...\n"; vidfile.close(); throw 42; } vidfile.write((char*)vidpage.body, vidpage.body_len); if (!vidfile) { std::cerr << "An error occured in writing Ogg page body to file. Exiting...\n"; vidfile.close(); throw 42; } }; // send header packets to ogg stream bool gotone = false; while (true) { int mkpacket = th_encode_flushheader(videnc, &vidcomment, &vidpacket); if (mkpacket == 0) { if (gotone) { break; } else { std::cerr << "Theora didn't return any header packets.\n"; throw 42; } } if (mkpacket < 0) { std::cerr << "Theora header flushing failed with error code " << mkpacket << ". Exiting...\n"; throw 42; } if (ogg_stream_packetin(&vidcont, &vidpacket)) { std::cerr << "Giving packet to Ogg failed, sorry.\n"; throw 42; } gotone = true; } // write ogg pages (and then the remainder via flush) to file while (ogg_stream_pageout(&vidcont, &vidpage)) { writePage(); } while (ogg_stream_flush(&vidcont, &vidpage)) { writePage(); } ////////////////////// // WRITE THE FRAMES // ////////////////////// for (int FRNO = 0; FRNO < vidframes.size(); FRNO++) { auto * VFR = &vidframes.at(FRNO); // since we set an offset of (0,0) for the picture, we fill up the // top and right edges of the frame with junk. This is us filling // the top part for (int i = 0; i < padH; i++) { for (int j = 0; j < frmWidth; j++) { rawdata[Y].data[i * frmWidth + j] = 0; rawdata[Cb].data[i * frmWidth + j] = 0; rawdata[Cr].data[i * frmWidth + j] = 0; } } // now for the picture itself (every row we add more junk to the right // of the image) int vecAt = 0; // where we are in the VFR vector for (int i = 0; i < vidHeight; i++) { for (int j = 0; j < vidWidth; j++) { rawdata[Y].data[i * frmWidth + j] = VFR->at(vecAt); vecAt++; rawdata[Cb].data[i * frmWidth + j] = VFR->at(vecAt); vecAt++; rawdata[Cr].data[i * frmWidth + j] = VFR->at(vecAt); vecAt++; } // get right-side padding (fill with junk) for (int j = vidWidth; j < frmWidth; j++) { rawdata[Y].data[i * frmWidth + j] = 0; rawdata[Cb].data[i * frmWidth + j] = 0; rawdata[Cr].data[i * frmWidth + j] = 0; } } // frame made, send through theora if (th_encode_ycbcr_in(videnc, rawdata)) { std::cerr << "Error in sending frame " << FRNO + 1 << " of " << vidframes.size() << " to Theora.\n"; throw 42; } // send theora packets into ogg while (true) { int packok = th_encode_packetout(videnc, FRNO + 1 == vidframes.size(), &vidpacket); if (packok == 0) { break; } if (packok < 0) { std::cerr << "Retrieving packet from Theora failed with error code " << packok << ".\n"; throw 42; } if (ogg_stream_packetin(&vidcont, &vidpacket)) { std::cerr << "Giving frame packet to Ogg failed.\n"; throw 42; } } // send complete pages from frame to file (we won't flush until // after all frames are accounted for, to avoid an abundance of // undersized pages) while (ogg_stream_pageout(&vidcont, &vidpage)) { writePage(); } } // take care of any remaining undersized page(s) while (ogg_stream_flush(&vidcont, &vidpage)) { writePage(); } //// Free/close/etc all relevant structures // fstream vidfile.close(); // theora items //th_encode_free(videnc); // causes a corrupted double-linked list, somehow, so you'll have to live with unfree'd memory :( th_info_clear(&vidinfo); th_comment_clear(&vidcomment); for (auto & i : rawdata) { delete[] i.data; } // ogg items ogg_packet_clear(&vidpacket); ogg_stream_clear(&vidcont); }
static av_cold int encode_init(AVCodecContext* avc_context) { th_info t_info; th_comment t_comment; ogg_packet o_packet; unsigned int offset; TheoraContext *h = avc_context->priv_data; uint32_t gop_size = avc_context->gop_size; /* Set up the theora_info struct */ th_info_init(&t_info); t_info.frame_width = FFALIGN(avc_context->width, 16); t_info.frame_height = FFALIGN(avc_context->height, 16); t_info.pic_width = avc_context->width; t_info.pic_height = avc_context->height; t_info.pic_x = 0; t_info.pic_y = 0; /* Swap numerator and denominator as time_base in AVCodecContext gives the * time period between frames, but theora_info needs the framerate. */ t_info.fps_numerator = avc_context->time_base.den; t_info.fps_denominator = avc_context->time_base.num; if (avc_context->sample_aspect_ratio.num) { t_info.aspect_numerator = avc_context->sample_aspect_ratio.num; t_info.aspect_denominator = avc_context->sample_aspect_ratio.den; } else { t_info.aspect_numerator = 1; t_info.aspect_denominator = 1; } if (avc_context->color_primaries == AVCOL_PRI_BT470M) t_info.colorspace = TH_CS_ITU_REC_470M; else if (avc_context->color_primaries == AVCOL_PRI_BT470BG) t_info.colorspace = TH_CS_ITU_REC_470BG; else t_info.colorspace = TH_CS_UNSPECIFIED; if (avc_context->pix_fmt == AV_PIX_FMT_YUV420P) t_info.pixel_fmt = TH_PF_420; else if (avc_context->pix_fmt == AV_PIX_FMT_YUV422P) t_info.pixel_fmt = TH_PF_422; else if (avc_context->pix_fmt == AV_PIX_FMT_YUV444P) t_info.pixel_fmt = TH_PF_444; else { av_log(avc_context, AV_LOG_ERROR, "Unsupported pix_fmt\n"); return -1; } av_pix_fmt_get_chroma_sub_sample(avc_context->pix_fmt, &h->uv_hshift, &h->uv_vshift); if (avc_context->flags & CODEC_FLAG_QSCALE) { /* to be constant with the libvorbis implementation, clip global_quality to 0 - 10 Theora accepts a quality parameter p, which is: * 0 <= p <=63 * an int value */ t_info.quality = av_clipf(avc_context->global_quality / (float)FF_QP2LAMBDA, 0, 10) * 6.3; t_info.target_bitrate = 0; } else { t_info.target_bitrate = avc_context->bit_rate; t_info.quality = 0; } /* Now initialise libtheora */ h->t_state = th_encode_alloc(&t_info); if (!h->t_state) { av_log(avc_context, AV_LOG_ERROR, "theora_encode_init failed\n"); return -1; } h->keyframe_mask = (1 << t_info.keyframe_granule_shift) - 1; /* Clear up theora_info struct */ th_info_clear(&t_info); if (th_encode_ctl(h->t_state, TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE, &gop_size, sizeof(gop_size))) { av_log(avc_context, AV_LOG_ERROR, "Error setting GOP size\n"); return -1; } // need to enable 2 pass (via TH_ENCCTL_2PASS_) before encoding headers if (avc_context->flags & CODEC_FLAG_PASS1) { if (get_stats(avc_context, 0)) return -1; } else if (avc_context->flags & CODEC_FLAG_PASS2) { if (submit_stats(avc_context)) return -1; } /* Output first header packet consisting of theora header, comment, and tables. Each one is prefixed with a 16bit size, then they are concatenated together into libavcodec's extradata. */ offset = 0; /* Headers */ th_comment_init(&t_comment); while (th_encode_flushheader(h->t_state, &t_comment, &o_packet)) if (concatenate_packet(&offset, avc_context, &o_packet)) return -1; th_comment_clear(&t_comment); /* Set up the output AVFrame */ avc_context->coded_frame = av_frame_alloc(); return 0; }