aboutsummaryrefslogtreecommitdiffstats
path: root/src/kvilib/ext/KviOggTheoraEncoder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/kvilib/ext/KviOggTheoraEncoder.cpp')
-rw-r--r--src/kvilib/ext/KviOggTheoraEncoder.cpp253
1 files changed, 134 insertions, 119 deletions
diff --git a/src/kvilib/ext/KviOggTheoraEncoder.cpp b/src/kvilib/ext/KviOggTheoraEncoder.cpp
index a63e111af..27f613200 100644
--- a/src/kvilib/ext/KviOggTheoraEncoder.cpp
+++ b/src/kvilib/ext/KviOggTheoraEncoder.cpp
@@ -35,13 +35,15 @@
using namespace KviOggIrcText;
-static void rgb32toyuv444(QRgb * rgbPt, unsigned char *yuvPt, int w, int h)
+static void rgb32toyuv444(QRgb * rgbPt, unsigned char * yuvPt, int w, int h)
{
- for(int i = 0; i < h; i++) {
- for (int j = 0; j < w; j++) {
- yuvPt[i * w + j] = (unsigned char) (( 66 * qRed(*rgbPt) + 129 * qGreen(*rgbPt) + 25 * qBlue(*rgbPt) + 128) >> 8) + 16; // y
- yuvPt[(i + h) * w + j] = (unsigned char) ((-38 * qRed(*rgbPt) - 74 * qGreen(*rgbPt) + 112 * qBlue(*rgbPt) + 128) >> 8) + 128; // u
- yuvPt[(i + 2 * h) * w + j] = (unsigned char) ((112 * qRed(*rgbPt) - 94 * qGreen(*rgbPt) - 18 * qBlue(*rgbPt) + 128) >> 8) + 128; // v
+ for(int i = 0; i < h; i++)
+ {
+ for(int j = 0; j < w; j++)
+ {
+ yuvPt[i * w + j] = (unsigned char)((66 * qRed(*rgbPt) + 129 * qGreen(*rgbPt) + 25 * qBlue(*rgbPt) + 128) >> 8) + 16; // y
+ yuvPt[(i + h) * w + j] = (unsigned char)((-38 * qRed(*rgbPt) - 74 * qGreen(*rgbPt) + 112 * qBlue(*rgbPt) + 128) >> 8) + 128; // u
+ yuvPt[(i + 2 * h) * w + j] = (unsigned char)((112 * qRed(*rgbPt) - 94 * qGreen(*rgbPt) - 18 * qBlue(*rgbPt) + 128) >> 8) + 128; // v
//this moves the pointer forward 4 bytes (ARGB)
rgbPt++;
}
@@ -49,48 +51,46 @@ static void rgb32toyuv444(QRgb * rgbPt, unsigned char *yuvPt, int w, int h)
return;
}
-
KviOggTheoraEncoder::KviOggTheoraEncoder(KviDataBuffer * stream, int iWidth, int iHeight, int iFpsN, int iFpsD, int iParN, int iParD)
{
//used to check functions results
int ret;
- videoflag=0;
- videoYuv=0;
- frame_state=-1;
+ videoflag = 0;
+ videoYuv = 0;
+ frame_state = -1;
//text
- text_sofar=0;
+ text_sofar = 0;
//user settings
- m_pStream=stream;
- geometry.pic_w=iWidth;
- geometry.pic_h=iHeight;
+ m_pStream = stream;
+ geometry.pic_w = iWidth;
+ geometry.pic_h = iHeight;
//frame per second
- int video_fps_n=iFpsN;
- int video_fps_d=iFpsD;
+ int video_fps_n = iFpsN;
+ int video_fps_d = iFpsD;
//aspect ratio
- int video_par_n=iParN;
- int video_par_d=iParD;
-
+ int video_par_n = iParN;
+ int video_par_d = iParD;
// preset settings
- int video_q=48;
- ogg_uint32_t keyframe_frequency=64;
+ int video_q = 48;
+ ogg_uint32_t keyframe_frequency = 64;
- y4m_dst_buf_read_sz = geometry.pic_w * geometry.pic_h * 3;
- y4m_aux_buf_sz = y4m_aux_buf_read_sz=0;
+ y4m_dst_buf_read_sz = geometry.pic_w * geometry.pic_h * 3;
+ y4m_aux_buf_sz = y4m_aux_buf_read_sz = 0;
// buffer allocations
y4m_dst_buf_read_sz = geometry.pic_w * geometry.pic_h * 3;
- y4m_aux_buf_sz = y4m_aux_buf_read_sz=0;
+ y4m_aux_buf_sz = y4m_aux_buf_read_sz = 0;
// The size of the final frame buffers is always computed from the destination chroma decimation type.
y4m_dst_buf_sz = geometry.pic_w * geometry.pic_h * 3;
// Set up Ogg output stream
srand(time(NULL));
- ogg_stream_init(&to,rand());
+ ogg_stream_init(&to, rand());
- ogg_stream_init(&zo,rand());
+ ogg_stream_init(&zo, rand());
ret = irct_encode_init();
if(ret)
{
@@ -98,37 +98,37 @@ KviOggTheoraEncoder::KviOggTheoraEncoder(KviDataBuffer * stream, int iWidth, int
return;
}
-
// Set up Theora encoder
// Theora has a divisible-by-sixteen restriction for the encoded frame size
// scale the picture size up to the nearest /16 and calculate offsets
- geometry.frame_w = (geometry.pic_w + 15) &~ 0xF;
- geometry.frame_h = (geometry.pic_h + 15) &~ 0xF;
+ geometry.frame_w = (geometry.pic_w + 15) & ~0xF;
+ geometry.frame_h = (geometry.pic_h + 15) & ~0xF;
// Force the offsets to be even so that chroma samples line up like we expect.
- geometry.pic_x = (geometry.frame_w - geometry.pic_w) >> 1 &~ 1;
- geometry.pic_y = (geometry.frame_h - geometry.pic_h) >> 1 &~ 1;
+ geometry.pic_x = (geometry.frame_w - geometry.pic_w) >> 1 & ~1;
+ geometry.pic_y = (geometry.frame_h - geometry.pic_h) >> 1 & ~1;
// Fill in a th_info structure with details on the format of the video you wish to encode.
th_info_init(&ti);
- ti.frame_width=geometry.frame_w;
- ti.frame_height=geometry.frame_h;
- ti.pic_width=geometry.pic_w;
- ti.pic_height=geometry.pic_h;
- ti.pic_x=geometry.pic_x;
- ti.pic_y=geometry.pic_y;
- ti.fps_numerator=video_fps_n;
- ti.fps_denominator=video_fps_d;
- ti.aspect_numerator=video_par_n;
- ti.aspect_denominator=video_par_d;
- ti.colorspace=TH_CS_UNSPECIFIED;
+ ti.frame_width = geometry.frame_w;
+ ti.frame_height = geometry.frame_h;
+ ti.pic_width = geometry.pic_w;
+ ti.pic_height = geometry.pic_h;
+ ti.pic_x = geometry.pic_x;
+ ti.pic_y = geometry.pic_y;
+ ti.fps_numerator = video_fps_n;
+ ti.fps_denominator = video_fps_d;
+ ti.aspect_numerator = video_par_n;
+ ti.aspect_denominator = video_par_d;
+ ti.colorspace = TH_CS_UNSPECIFIED;
//use vbr, not cbr
- ti.target_bitrate=0;
- ti.quality=video_q;
- ti.keyframe_granule_shift=ilog(keyframe_frequency-1);
- ti.pixel_fmt=TH_PF_444;
+ ti.target_bitrate = 0;
+ ti.quality = video_q;
+ ti.keyframe_granule_shift = ilog(keyframe_frequency - 1);
+ ti.pixel_fmt = TH_PF_444;
// Allocate a th_enc_ctx handle with th_encode_alloc().
- td=th_encode_alloc(&ti);
- if(td==0){
+ td = th_encode_alloc(&ti);
+ if(td == 0)
+ {
qDebug("Could not th_encode_alloc().");
return;
}
@@ -136,64 +136,73 @@ KviOggTheoraEncoder::KviOggTheoraEncoder(KviDataBuffer * stream, int iWidth, int
th_info_clear(&ti);
// Perform any additional encoder configuration required with th_encode_ctl().
// setting just the granule shift only allows power-of-two keyframe spacing. Set the actual requested spacing.
- ret=th_encode_ctl(td,TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,&keyframe_frequency,sizeof(keyframe_frequency-1));
- if(ret<0){
- qDebug("Could not set keyframe interval to %d.",(int)keyframe_frequency);
+ ret = th_encode_ctl(td, TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE, &keyframe_frequency, sizeof(keyframe_frequency - 1));
+ if(ret < 0)
+ {
+ qDebug("Could not set keyframe interval to %d.", (int)keyframe_frequency);
}
// write the bitstream header packets with proper page interleave
th_comment_init(&tc);
// Repeatedly call th_encode_flushheader() to retrieve all the header packets.
// first packet will get its own page automatically
- if(th_encode_flushheader(td,&tc,&op)<=0){
+ if(th_encode_flushheader(td, &tc, &op) <= 0)
+ {
qDebug("Internal Theora library error.");
return;
}
- ogg_stream_packetin(&to,&op);
- if(ogg_stream_pageout(&to,&og)!=1){
+ ogg_stream_packetin(&to, &op);
+ if(ogg_stream_pageout(&to, &og) != 1)
+ {
qDebug("Internal Ogg library error.");
return;
}
- m_pStream->append(og.header,og.header_len);
- m_pStream->append(og.body,og.body_len);
+ m_pStream->append(og.header, og.header_len);
+ m_pStream->append(og.body, og.body_len);
// create the remaining theora headers
- for(;;){
- ret=th_encode_flushheader(td,&tc,&op);
- if(ret<0){
+ for(;;)
+ {
+ ret = th_encode_flushheader(td, &tc, &op);
+ if(ret < 0)
+ {
qDebug("Internal Theora library error.");
return;
}
- else if(!ret)break;
- ogg_stream_packetin(&to,&op);
+ else if(!ret)
+ break;
+ ogg_stream_packetin(&to, &op);
}
//irct
ogg_packet header;
irct_encode_headerout(&header);
- ogg_stream_packetin(&zo,&header); // automatically placed in its own page
- if(ogg_stream_pageout(&zo,&og)!=1){
+ ogg_stream_packetin(&zo, &header); // automatically placed in its own page
+ if(ogg_stream_pageout(&zo, &og) != 1)
+ {
qDebug("Internal Ogg library error (irct).");
return;
}
- m_pStream->append(og.header,og.header_len);
- m_pStream->append(og.body,og.body_len);
+ m_pStream->append(og.header, og.header_len);
+ m_pStream->append(og.body, og.body_len);
// Flush the rest of our headers. This ensures the actual data in each stream
// will start on a new page, as per spec.
for(;;)
{
- int result = ogg_stream_flush(&to,&og);
- if(result<0){
+ int result = ogg_stream_flush(&to, &og);
+ if(result < 0)
+ {
// can't get here
qDebug("Internal Ogg library error.");
return;
}
- if(result==0)break;
- m_pStream->append(og.header,og.header_len);
- m_pStream->append(og.body,og.body_len);
+ if(result == 0)
+ break;
+ m_pStream->append(og.header, og.header_len);
+ m_pStream->append(og.body, og.body_len);
}
}
@@ -222,25 +231,26 @@ void KviOggTheoraEncoder::addVideoFrame(QRgb * rgb32, int)
videoYuv = new quint8[geometry.pic_w * geometry.pic_h * YUV444_BPP];
rgb32toyuv444(rgb32, videoYuv, geometry.pic_w, geometry.pic_h);
-// qDebug("addFrame p%p size%d yuv%p",rgb32,videoSize,videoYuv);
+ // qDebug("addFrame p%p size%d yuv%p",rgb32,videoSize,videoYuv);
ogg_page videopage;
// is there a video page flushed? If not, fetch one if possible
- videoflag=fetch_and_process_video(videoYuv,&videopage,&to,td,videoflag);
+ videoflag = fetch_and_process_video(videoYuv, &videopage, &to, td, videoflag);
// no pages?
- if(!videoflag) return;
+ if(!videoflag)
+ return;
- th_granule_time(td,ogg_page_granulepos(&videopage));
+ th_granule_time(td, ogg_page_granulepos(&videopage));
// flush a video page
- m_pStream->append(videopage.header,videopage.header_len);
- m_pStream->append(videopage.body,videopage.body_len);
- videoflag=0;
+ m_pStream->append(videopage.header, videopage.header_len);
+ m_pStream->append(videopage.body, videopage.body_len);
+ videoflag = 0;
}
-void KviOggTheoraEncoder::addTextFrame(unsigned char* textPkt, int textSize)
+void KviOggTheoraEncoder::addTextFrame(unsigned char * textPkt, int textSize)
{
ogg_page textpage;
ogg_packet op;
@@ -248,46 +258,47 @@ void KviOggTheoraEncoder::addTextFrame(unsigned char* textPkt, int textSize)
text_sofar++;
// is there an audio page flushed? If not, fetch one if possible
- textflag=irct_encode_packetout((char *) textPkt, textSize, text_sofar,&op);
+ textflag = irct_encode_packetout((char *)textPkt, textSize, text_sofar, &op);
ogg_stream_packetin(&zo, &op);
ogg_stream_pageout(&zo, &textpage);
// no pages? Must be end of stream.
-// if(!textflag) return;
+ // if(!textflag) return;
- m_pStream->append(textpage.header,textpage.header_len);
- m_pStream->append(textpage.body,textpage.body_len);
- textflag=0;
+ m_pStream->append(textpage.header, textpage.header_len);
+ m_pStream->append(textpage.body, textpage.body_len);
+ textflag = 0;
}
-int KviOggTheoraEncoder::fetch_and_process_video_packet(quint8 * videoYuv,th_enc_ctx *td,ogg_packet *op)
+int KviOggTheoraEncoder::fetch_and_process_video_packet(quint8 * videoYuv, th_enc_ctx * td, ogg_packet * op)
{
th_ycbcr_buffer ycbcr;
- if(frame_state==-1)
+ if(frame_state == -1)
{
/* initialize the double frame buffer */
- yuvframe[0]=(unsigned char *)malloc(y4m_dst_buf_sz);
- yuvframe[1]=(unsigned char *)malloc(y4m_dst_buf_sz);
- yuvframe[2]=(unsigned char *)malloc(y4m_aux_buf_sz);
- frame_state=0;
+ yuvframe[0] = (unsigned char *)malloc(y4m_dst_buf_sz);
+ yuvframe[1] = (unsigned char *)malloc(y4m_dst_buf_sz);
+ yuvframe[2] = (unsigned char *)malloc(y4m_aux_buf_sz);
+ frame_state = 0;
}
/* read and process more video */
/* have two frame buffers full (if possible) before
proceeding. after first pass and until eos, one will
always be full when we get here */
- for(;frame_state<2;)
+ for(; frame_state < 2;)
{
/*Read the frame data that needs no conversion.*/
- memcpy(yuvframe[frame_state],videoYuv,y4m_dst_buf_read_sz);
+ memcpy(yuvframe[frame_state], videoYuv, y4m_dst_buf_read_sz);
/*Read the frame data that does need conversion.*/
- memcpy(yuvframe[2],videoYuv,y4m_aux_buf_read_sz);
+ memcpy(yuvframe[2], videoYuv, y4m_aux_buf_read_sz);
frame_state++;
}
/* check to see if there are dupes to flush */
- if(th_encode_packetout(td,frame_state<1,op)>0)return 1;
- if(frame_state<1)
+ if(th_encode_packetout(td, frame_state < 1, op) > 0)
+ return 1;
+ if(frame_state < 1)
{
/* can't get here unless YUV4MPEG stream has no video */
qDebug("Video input contains no frames.");
@@ -300,34 +311,34 @@ int KviOggTheoraEncoder::fetch_and_process_video_packet(quint8 * videoYuv,th_enc
actually allocate space for the padding.
This is okay, because with the 1.0 API the library will never read data from the padded
region.*/
- ycbcr[0].width=geometry.frame_w;
- ycbcr[0].height=geometry.frame_h;
- ycbcr[0].stride=geometry.pic_w;
- ycbcr[0].data=yuvframe[0] - geometry.pic_x -geometry.pic_y * geometry.pic_w;
+ ycbcr[0].width = geometry.frame_w;
+ ycbcr[0].height = geometry.frame_h;
+ ycbcr[0].stride = geometry.pic_w;
+ ycbcr[0].data = yuvframe[0] - geometry.pic_x - geometry.pic_y * geometry.pic_w;
- ycbcr[1].width=geometry.frame_w;
- ycbcr[1].height=geometry.frame_h;
- ycbcr[1].stride=geometry.pic_w;
- ycbcr[1].data=yuvframe[0] + (geometry.pic_w * geometry.pic_h) - geometry.pic_x - geometry.pic_y * geometry.frame_w;
+ ycbcr[1].width = geometry.frame_w;
+ ycbcr[1].height = geometry.frame_h;
+ ycbcr[1].stride = geometry.pic_w;
+ ycbcr[1].data = yuvframe[0] + (geometry.pic_w * geometry.pic_h) - geometry.pic_x - geometry.pic_y * geometry.frame_w;
- ycbcr[2].width=geometry.frame_w;
- ycbcr[2].height=geometry.frame_h;
- ycbcr[2].stride=geometry.pic_w;
- ycbcr[2].data=ycbcr[1].data+(geometry.frame_w * geometry.frame_h);
+ ycbcr[2].width = geometry.frame_w;
+ ycbcr[2].height = geometry.frame_h;
+ ycbcr[2].stride = geometry.pic_w;
+ ycbcr[2].data = ycbcr[1].data + (geometry.frame_w * geometry.frame_h);
- th_encode_ycbcr_in(td,ycbcr);
+ th_encode_ycbcr_in(td, ycbcr);
{
- unsigned char *temp=yuvframe[0];
- yuvframe[0]=yuvframe[1];
- yuvframe[1]=temp;
+ unsigned char * temp = yuvframe[0];
+ yuvframe[0] = yuvframe[1];
+ yuvframe[1] = temp;
frame_state--;
}
/* if there was only one frame, it's the last in the stream */
- return th_encode_packetout(td,frame_state<1,op);
+ return th_encode_packetout(td, frame_state < 1, op);
}
-int KviOggTheoraEncoder::fetch_and_process_video(quint8 * videoYuv,ogg_page *videopage,
-ogg_stream_state *to,th_enc_ctx *td,int videoflag)
+int KviOggTheoraEncoder::fetch_and_process_video(quint8 * videoYuv, ogg_page * videopage,
+ ogg_stream_state * to, th_enc_ctx * td, int videoflag)
{
ogg_packet op;
int ret;
@@ -335,11 +346,14 @@ ogg_stream_state *to,th_enc_ctx *td,int videoflag)
while(!videoflag)
{
//qDebug("fetch_and_process_video loop");
- if(ogg_stream_pageout(to,videopage)>0) return 1;
- if(ogg_stream_eos(to)) return 0;
- ret=fetch_and_process_video_packet(videoYuv,td,&op);
- if(ret<=0)return 0;
- ogg_stream_packetin(to,&op);
+ if(ogg_stream_pageout(to, videopage) > 0)
+ return 1;
+ if(ogg_stream_eos(to))
+ return 0;
+ ret = fetch_and_process_video_packet(videoYuv, td, &op);
+ if(ret <= 0)
+ return 0;
+ ogg_stream_packetin(to, &op);
}
return videoflag;
}
@@ -347,7 +361,8 @@ ogg_stream_state *to,th_enc_ctx *td,int videoflag)
int KviOggTheoraEncoder::ilog(unsigned _v)
{
int ret;
- for(ret=0;_v;ret++)_v>>=1;
+ for(ret = 0; _v; ret++)
+ _v >>= 1;
return ret;
}