| 1 | /* |
|---|
| 2 | mediastreamer2 library - modular sound and video processing and streaming |
|---|
| 3 | Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) |
|---|
| 4 | |
|---|
| 5 | This program is free software; you can redistribute it and/or |
|---|
| 6 | modify it under the terms of the GNU General Public License |
|---|
| 7 | as published by the Free Software Foundation; either version 2 |
|---|
| 8 | of the License, or (at your option) any later version. |
|---|
| 9 | |
|---|
| 10 | This program is distributed in the hope that it will be useful, |
|---|
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 13 | GNU General Public License for more details. |
|---|
| 14 | |
|---|
| 15 | You should have received a copy of the GNU General Public License |
|---|
| 16 | along with this program; if not, write to the Free Software |
|---|
| 17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
|---|
| 18 | */ |
|---|
| 19 | |
|---|
| 20 | #include "mediastreamer2/msfilter.h" |
|---|
| 21 | #include "mediastreamer2/msticker.h" |
|---|
| 22 | #include "mediastreamer2/msvideo.h" |
|---|
| 23 | |
|---|
| 24 | #include <theora/theora.h> |
|---|
| 25 | |
|---|
| 26 | typedef struct EncState{ |
|---|
| 27 | theora_state tstate; |
|---|
| 28 | theora_info tinfo; |
|---|
| 29 | yuv_buffer yuv; |
|---|
| 30 | mblk_t *packed_conf; |
|---|
| 31 | uint64_t start_time; |
|---|
| 32 | uint64_t conf_time; |
|---|
| 33 | unsigned int mtu; |
|---|
| 34 | } EncState; |
|---|
| 35 | |
|---|
| 36 | static void enc_init(MSFilter *f){ |
|---|
| 37 | EncState *s=(EncState *)ms_new(EncState,1); |
|---|
| 38 | theora_info_init(&s->tinfo); |
|---|
| 39 | s->tinfo.width=MS_VIDEO_SIZE_CIF_W; |
|---|
| 40 | s->tinfo.height=MS_VIDEO_SIZE_CIF_H; |
|---|
| 41 | s->tinfo.frame_width=MS_VIDEO_SIZE_CIF_W; |
|---|
| 42 | s->tinfo.frame_height=MS_VIDEO_SIZE_CIF_H; |
|---|
| 43 | s->tinfo.offset_x=0; |
|---|
| 44 | s->tinfo.offset_y=0; |
|---|
| 45 | s->tinfo.target_bitrate=500000; |
|---|
| 46 | s->tinfo.pixelformat=OC_PF_420; |
|---|
| 47 | s->tinfo.fps_numerator=15; |
|---|
| 48 | s->tinfo.fps_denominator=1; |
|---|
| 49 | s->tinfo.aspect_numerator=1; |
|---|
| 50 | s->tinfo.aspect_denominator=1; |
|---|
| 51 | s->tinfo.colorspace=OC_CS_UNSPECIFIED; |
|---|
| 52 | s->tinfo.dropframes_p=0; |
|---|
| 53 | s->tinfo.quick_p=1; |
|---|
| 54 | s->tinfo.quality=63; |
|---|
| 55 | s->tinfo.keyframe_auto_p=1; |
|---|
| 56 | s->tinfo.keyframe_frequency=64; |
|---|
| 57 | s->tinfo.keyframe_frequency_force=64; |
|---|
| 58 | s->tinfo.keyframe_data_target_bitrate=s->tinfo.target_bitrate*1.2; |
|---|
| 59 | s->tinfo.keyframe_auto_threshold=80; |
|---|
| 60 | s->tinfo.keyframe_mindistance=8; |
|---|
| 61 | s->tinfo.noise_sensitivity=1; |
|---|
| 62 | s->packed_conf=NULL; |
|---|
| 63 | s->start_time=0; |
|---|
| 64 | s->conf_time=0; |
|---|
| 65 | s->mtu=ms_get_payload_max_size()-6; |
|---|
| 66 | f->data=s; |
|---|
| 67 | } |
|---|
| 68 | |
|---|
| 69 | static void enc_uninit(MSFilter *f){ |
|---|
| 70 | EncState *s=(EncState*)f->data; |
|---|
| 71 | theora_info_clear(&s->tinfo); |
|---|
| 72 | ms_free(s); |
|---|
| 73 | } |
|---|
| 74 | |
|---|
| 75 | static int enc_set_vsize(MSFilter *f, void*data){ |
|---|
| 76 | MSVideoSize *vs=(MSVideoSize*)data; |
|---|
| 77 | EncState *s=(EncState*)f->data; |
|---|
| 78 | s->tinfo.width=vs->width; |
|---|
| 79 | s->tinfo.height=vs->height; |
|---|
| 80 | s->tinfo.frame_width=vs->width; |
|---|
| 81 | s->tinfo.frame_height=vs->height; |
|---|
| 82 | return 0; |
|---|
| 83 | } |
|---|
| 84 | |
|---|
| 85 | static int enc_get_vsize(MSFilter *f, void *data){ |
|---|
| 86 | EncState *s=(EncState*)f->data; |
|---|
| 87 | MSVideoSize *vs=(MSVideoSize*)data; |
|---|
| 88 | vs->width=s->tinfo.width; |
|---|
| 89 | vs->height=s->tinfo.height; |
|---|
| 90 | return 0; |
|---|
| 91 | } |
|---|
| 92 | |
|---|
| 93 | static int enc_add_attr(MSFilter *f, void*data){ |
|---|
| 94 | /*const char *attr=(const char*)data; |
|---|
| 95 | EncState *s=(EncState*)f->data;*/ |
|---|
| 96 | return 0; |
|---|
| 97 | } |
|---|
| 98 | |
|---|
| 99 | static int enc_set_fps(MSFilter *f, void *data){ |
|---|
| 100 | float *fps=(float*)data; |
|---|
| 101 | EncState *s=(EncState*)f->data; |
|---|
| 102 | s->tinfo.fps_numerator=*fps; |
|---|
| 103 | s->tinfo.keyframe_frequency=(*fps)*5; |
|---|
| 104 | s->tinfo.keyframe_frequency_force=(*fps)*5; |
|---|
| 105 | return 0; |
|---|
| 106 | } |
|---|
| 107 | |
|---|
| 108 | static int enc_get_fps(MSFilter *f, void *data){ |
|---|
| 109 | EncState *s=(EncState*)f->data; |
|---|
| 110 | float *fps=(float*)data; |
|---|
| 111 | *fps=s->tinfo.fps_numerator; |
|---|
| 112 | return 0; |
|---|
| 113 | } |
|---|
| 114 | |
|---|
| 115 | static int enc_set_br(MSFilter *f, void*data){ |
|---|
| 116 | int br=*(int*)data; |
|---|
| 117 | EncState *s=(EncState*)f->data; |
|---|
| 118 | MSVideoSize vsize; |
|---|
| 119 | float fps; |
|---|
| 120 | float codecbr=(float)br; |
|---|
| 121 | vsize.width=s->tinfo.width; |
|---|
| 122 | vsize.height=s->tinfo.height; |
|---|
| 123 | fps=s->tinfo.fps_numerator; |
|---|
| 124 | s->tinfo.target_bitrate=codecbr*0.8; |
|---|
| 125 | s->tinfo.keyframe_data_target_bitrate=codecbr; |
|---|
| 126 | /*those default settings would need to be affined*/ |
|---|
| 127 | if (br>=1024000){ |
|---|
| 128 | vsize.width = MS_VIDEO_SIZE_4CIF_W; |
|---|
| 129 | vsize.height = MS_VIDEO_SIZE_4CIF_H; |
|---|
| 130 | s->tinfo.quality=32; |
|---|
| 131 | fps=15; |
|---|
| 132 | }else if (br>=512000){ |
|---|
| 133 | vsize.width = MS_VIDEO_SIZE_CIF_W; |
|---|
| 134 | vsize.height = MS_VIDEO_SIZE_CIF_H; |
|---|
| 135 | s->tinfo.quality=32; |
|---|
| 136 | fps=15; |
|---|
| 137 | }else if (br>=256000){ |
|---|
| 138 | vsize.width = MS_VIDEO_SIZE_CIF_W; |
|---|
| 139 | vsize.height = MS_VIDEO_SIZE_CIF_H; |
|---|
| 140 | s->tinfo.quality=5; |
|---|
| 141 | fps=12; |
|---|
| 142 | }else if(br>=128000){ |
|---|
| 143 | vsize.width=MS_VIDEO_SIZE_QCIF_W; |
|---|
| 144 | vsize.height=MS_VIDEO_SIZE_QCIF_H; |
|---|
| 145 | s->tinfo.quality=20; |
|---|
| 146 | fps=10; |
|---|
| 147 | }else if(br>=64000){ |
|---|
| 148 | vsize.width=MS_VIDEO_SIZE_QCIF_W; |
|---|
| 149 | vsize.height=MS_VIDEO_SIZE_QCIF_H; |
|---|
| 150 | s->tinfo.quality=7; |
|---|
| 151 | fps=7; |
|---|
| 152 | } |
|---|
| 153 | enc_set_vsize(f,&vsize); |
|---|
| 154 | enc_set_fps(f,&fps); |
|---|
| 155 | return 0; |
|---|
| 156 | } |
|---|
| 157 | |
|---|
| 158 | static int enc_set_mtu(MSFilter *f, void*data){ |
|---|
| 159 | EncState *s=(EncState*)f->data; |
|---|
| 160 | s->mtu=*(int*)data; |
|---|
| 161 | return 0; |
|---|
| 162 | } |
|---|
| 163 | |
|---|
| 164 | #define THEORA_RAW_DATA 0 |
|---|
| 165 | #define THEORA_PACKED_CONF 1 |
|---|
| 166 | #define THEORA_COMMENT 2 |
|---|
| 167 | #define THEORA_RESERVED 3 |
|---|
| 168 | |
|---|
| 169 | #define NOT_FRAGMENTED 0 |
|---|
| 170 | #define START_FRAGMENT 1 |
|---|
| 171 | #define CONT_FRAGMENT 2 |
|---|
| 172 | #define END_FRAGMENT 3 |
|---|
| 173 | |
|---|
| 174 | |
|---|
| 175 | static inline void payload_header_set(uint8_t *buf, uint32_t ident, uint8_t ft, uint8_t tdt, uint8_t pkts){ |
|---|
| 176 | uint32_t tmp; |
|---|
| 177 | tmp=((ident&0xFFFFFF)<<8) | ((ft&0x3)<<6) | ((tdt&0x3)<<4) | (pkts&0xf); |
|---|
| 178 | *((uint32_t*)buf)=htonl(tmp); |
|---|
| 179 | } |
|---|
| 180 | |
|---|
| 181 | static inline uint32_t payload_header_get_ident(uint8_t *buf){ |
|---|
| 182 | uint32_t *tmp=(uint32_t*)buf; |
|---|
| 183 | return (ntohl(*tmp)>>8) & 0xFFFFFF; |
|---|
| 184 | } |
|---|
| 185 | |
|---|
| 186 | static inline uint32_t payload_header_get_tdt(uint8_t *buf){ |
|---|
| 187 | uint32_t *tmp=(uint32_t*)buf; |
|---|
| 188 | return ((ntohl(*tmp))>>4) & 0x3; |
|---|
| 189 | } |
|---|
| 190 | |
|---|
| 191 | static inline uint32_t payload_header_get_ft(uint8_t *buf){ |
|---|
| 192 | uint32_t *tmp=(uint32_t*)buf; |
|---|
| 193 | return ((ntohl(*tmp))>>6) & 0x3; |
|---|
| 194 | } |
|---|
| 195 | |
|---|
| 196 | static inline uint32_t payload_header_get_pkts(uint8_t *buf){ |
|---|
| 197 | uint32_t *tmp=(uint32_t*)buf; |
|---|
| 198 | return ntohl(*tmp) & 0xf; |
|---|
| 199 | } |
|---|
| 200 | |
|---|
| 201 | static int create_packed_conf(EncState *s){ |
|---|
| 202 | ogg_packet p; |
|---|
| 203 | theora_state *tstate=&s->tstate; |
|---|
| 204 | mblk_t *h,*t; |
|---|
| 205 | if (theora_encode_header(tstate,&p)!=0){ |
|---|
| 206 | ms_error("theora_encode_header() error."); |
|---|
| 207 | return -1; |
|---|
| 208 | } |
|---|
| 209 | h=allocb(p.bytes,0); |
|---|
| 210 | memcpy(h->b_wptr,p.packet,p.bytes); |
|---|
| 211 | h->b_wptr+=p.bytes; |
|---|
| 212 | if (theora_encode_tables(tstate,&p)!=0){ |
|---|
| 213 | ms_error("theora_encode_tables error."); |
|---|
| 214 | freemsg(h); |
|---|
| 215 | return -1; |
|---|
| 216 | } |
|---|
| 217 | t=allocb(p.bytes,0); |
|---|
| 218 | memcpy(t->b_wptr,p.packet,p.bytes); |
|---|
| 219 | t->b_wptr+=p.bytes; |
|---|
| 220 | h->b_cont=t; |
|---|
| 221 | msgpullup(h,-1); |
|---|
| 222 | s->packed_conf=h; |
|---|
| 223 | return 0; |
|---|
| 224 | } |
|---|
| 225 | |
|---|
| 226 | static void enc_preprocess(MSFilter *f){ |
|---|
| 227 | EncState *s=(EncState*)f->data; |
|---|
| 228 | int err; |
|---|
| 229 | if ((err=theora_encode_init(&s->tstate,&s->tinfo))!=0){ |
|---|
| 230 | ms_error("error in theora_encode_init() : %i !",err); |
|---|
| 231 | } |
|---|
| 232 | s->yuv.y_width=s->tinfo.width; |
|---|
| 233 | s->yuv.y_height=s->tinfo.height; |
|---|
| 234 | s->yuv.y_stride=s->tinfo.width; |
|---|
| 235 | s->yuv.uv_width=s->tinfo.width/2; |
|---|
| 236 | s->yuv.uv_height=s->tinfo.height/2; |
|---|
| 237 | s->yuv.uv_stride=s->tinfo.width/2; |
|---|
| 238 | create_packed_conf(s); |
|---|
| 239 | s->conf_time=0; |
|---|
| 240 | s->start_time=f->ticker->time; |
|---|
| 241 | } |
|---|
| 242 | |
|---|
| 243 | static void enc_postprocess(MSFilter *f){ |
|---|
| 244 | EncState *s=(EncState*)f->data; |
|---|
| 245 | theora_clear(&s->tstate); |
|---|
| 246 | |
|---|
| 247 | //If preprocess is called after postprocess, |
|---|
| 248 | //then we loose all info... |
|---|
| 249 | //theora_info_clear(&s->tinfo); |
|---|
| 250 | |
|---|
| 251 | if (s->packed_conf) { |
|---|
| 252 | freemsg(s->packed_conf); |
|---|
| 253 | s->packed_conf=NULL; |
|---|
| 254 | } |
|---|
| 255 | } |
|---|
| 256 | |
|---|
| 257 | static void enc_fill_yuv(yuv_buffer *yuv, mblk_t *im){ |
|---|
| 258 | yuv->y=(uint8_t*)im->b_rptr; |
|---|
| 259 | yuv->u=(uint8_t*)im->b_rptr+(yuv->y_stride*yuv->y_height); |
|---|
| 260 | yuv->v=(uint8_t*)yuv->u+(yuv->uv_stride*yuv->uv_height); |
|---|
| 261 | } |
|---|
| 262 | |
|---|
| 263 | |
|---|
| 264 | static void packetize_and_send(MSFilter *f, EncState *s, mblk_t *om, uint32_t timestamp, uint8_t tdt){ |
|---|
| 265 | mblk_t *packet; |
|---|
| 266 | mblk_t *h; |
|---|
| 267 | int npackets=0; |
|---|
| 268 | static const int ident=0xdede; |
|---|
| 269 | while(om!=NULL){ |
|---|
| 270 | if (om->b_wptr-om->b_rptr>=s->mtu){ |
|---|
| 271 | packet=dupb(om); |
|---|
| 272 | packet->b_wptr=packet->b_rptr+s->mtu; |
|---|
| 273 | om->b_rptr=packet->b_wptr; |
|---|
| 274 | }else { |
|---|
| 275 | packet=om; |
|---|
| 276 | om=NULL; |
|---|
| 277 | } |
|---|
| 278 | ++npackets; |
|---|
| 279 | h=allocb(6,0); |
|---|
| 280 | if (npackets==1){ |
|---|
| 281 | if (om==NULL) |
|---|
| 282 | payload_header_set(h->b_wptr,ident,NOT_FRAGMENTED,tdt,1); |
|---|
| 283 | else |
|---|
| 284 | payload_header_set(h->b_wptr,ident,START_FRAGMENT,tdt,1); |
|---|
| 285 | }else{ |
|---|
| 286 | if (om==NULL) |
|---|
| 287 | payload_header_set(h->b_wptr,ident,END_FRAGMENT,tdt,1); |
|---|
| 288 | else |
|---|
| 289 | payload_header_set(h->b_wptr,ident,CONT_FRAGMENT,tdt,1); |
|---|
| 290 | } |
|---|
| 291 | h->b_wptr+=4; |
|---|
| 292 | *((uint16_t*)h->b_wptr)=htons(msgdsize(packet)); |
|---|
| 293 | h->b_wptr+=2; |
|---|
| 294 | h->b_cont=packet; |
|---|
| 295 | mblk_set_timestamp_info(h,timestamp); |
|---|
| 296 | ms_debug("sending theora frame of size %i",msgdsize(h)); |
|---|
| 297 | ms_queue_put(f->outputs[0],h); |
|---|
| 298 | } |
|---|
| 299 | } |
|---|
| 300 | |
|---|
| 301 | bool_t need_send_conf(EncState *s, uint64_t elapsed){ |
|---|
| 302 | #ifdef AMD_HACK |
|---|
| 303 | if (elapsed<5000 && elapsed>=s->conf_time){ |
|---|
| 304 | s->conf_time+=500; |
|---|
| 305 | return TRUE; |
|---|
| 306 | } |
|---|
| 307 | #else |
|---|
| 308 | /*send immediately then 10 seconds later */ |
|---|
| 309 | if ( (elapsed<1000 && s->conf_time==0) |
|---|
| 310 | || (elapsed>10000 && s->conf_time==1)){ |
|---|
| 311 | s->conf_time++; |
|---|
| 312 | return TRUE; |
|---|
| 313 | } |
|---|
| 314 | #endif |
|---|
| 315 | return FALSE; |
|---|
| 316 | } |
|---|
| 317 | |
|---|
| 318 | static void enc_process(MSFilter *f){ |
|---|
| 319 | mblk_t *im,*om; |
|---|
| 320 | ogg_packet op; |
|---|
| 321 | EncState *s=(EncState*)f->data; |
|---|
| 322 | uint64_t timems=f->ticker->time; |
|---|
| 323 | uint32_t timestamp=timems*90; |
|---|
| 324 | uint64_t elapsed=timems-s->start_time; |
|---|
| 325 | while((im=ms_queue_get(f->inputs[0]))!=NULL){ |
|---|
| 326 | /*for the firsts frames only send theora packed conf*/ |
|---|
| 327 | om=NULL; |
|---|
| 328 | |
|---|
| 329 | if (need_send_conf(s,elapsed)){ |
|---|
| 330 | if (s->packed_conf) { |
|---|
| 331 | om=dupmsg(s->packed_conf); |
|---|
| 332 | ms_message("sending theora packed conf (%i bytes)",msgdsize(om)); |
|---|
| 333 | packetize_and_send(f,s,om,timestamp,THEORA_PACKED_CONF); |
|---|
| 334 | }else { |
|---|
| 335 | ms_error("No packed conf to send."); |
|---|
| 336 | } |
|---|
| 337 | }else{ |
|---|
| 338 | enc_fill_yuv(&s->yuv,im); |
|---|
| 339 | ms_debug("subtmitting yuv frame to theora encoder..."); |
|---|
| 340 | if (theora_encode_YUVin(&s->tstate,&s->yuv)!=0){ |
|---|
| 341 | ms_error("theora_encode_YUVin error."); |
|---|
| 342 | }else{ |
|---|
| 343 | if (theora_encode_packetout(&s->tstate,0,&op)==1){ |
|---|
| 344 | ms_debug("Got theora coded frame"); |
|---|
| 345 | om=allocb(op.bytes,0); |
|---|
| 346 | memcpy(om->b_wptr,op.packet,op.bytes); |
|---|
| 347 | om->b_wptr+=op.bytes; |
|---|
| 348 | packetize_and_send(f,s,om,timestamp,THEORA_RAW_DATA); |
|---|
| 349 | } |
|---|
| 350 | } |
|---|
| 351 | } |
|---|
| 352 | freemsg(im); |
|---|
| 353 | } |
|---|
| 354 | } |
|---|
| 355 | |
|---|
| 356 | static MSFilterMethod enc_methods[]={ |
|---|
| 357 | { MS_FILTER_SET_VIDEO_SIZE, enc_set_vsize }, |
|---|
| 358 | { MS_FILTER_SET_FPS, enc_set_fps }, |
|---|
| 359 | { MS_FILTER_GET_VIDEO_SIZE, enc_get_vsize }, |
|---|
| 360 | { MS_FILTER_GET_FPS, enc_get_fps }, |
|---|
| 361 | { MS_FILTER_ADD_ATTR, enc_add_attr }, |
|---|
| 362 | { MS_FILTER_SET_BITRATE, enc_set_br }, |
|---|
| 363 | { MS_FILTER_SET_MTU, enc_set_mtu }, |
|---|
| 364 | { 0 , NULL } |
|---|
| 365 | }; |
|---|
| 366 | |
|---|
| 367 | #ifdef _MSC_VER |
|---|
| 368 | |
|---|
| 369 | MSFilterDesc ms_theora_enc_desc={ |
|---|
| 370 | MS_THEORA_ENC_ID, |
|---|
| 371 | "MSTheoraEnc", |
|---|
| 372 | N_("The theora video encoder from xiph.org"), |
|---|
| 373 | MS_FILTER_ENCODER, |
|---|
| 374 | "theora", |
|---|
| 375 | 1, |
|---|
| 376 | 1, |
|---|
| 377 | enc_init, |
|---|
| 378 | enc_preprocess, |
|---|
| 379 | enc_process, |
|---|
| 380 | enc_postprocess, |
|---|
| 381 | enc_uninit, |
|---|
| 382 | enc_methods |
|---|
| 383 | }; |
|---|
| 384 | |
|---|
| 385 | #else |
|---|
| 386 | |
|---|
| 387 | MSFilterDesc ms_theora_enc_desc={ |
|---|
| 388 | .id=MS_THEORA_ENC_ID, |
|---|
| 389 | .name="MSTheoraEnc", |
|---|
| 390 | .text=N_("The open-source and royalty-free 'theora' video codec from xiph.org"), |
|---|
| 391 | .category=MS_FILTER_ENCODER, |
|---|
| 392 | .enc_fmt="theora", |
|---|
| 393 | .ninputs=1, |
|---|
| 394 | .noutputs=1, |
|---|
| 395 | .init=enc_init, |
|---|
| 396 | .preprocess=enc_preprocess, |
|---|
| 397 | .process=enc_process, |
|---|
| 398 | .postprocess=enc_postprocess, |
|---|
| 399 | .uninit=enc_uninit, |
|---|
| 400 | .methods=enc_methods |
|---|
| 401 | }; |
|---|
| 402 | |
|---|
| 403 | #endif |
|---|
| 404 | |
|---|
| 405 | MS_FILTER_DESC_EXPORT(ms_theora_enc_desc) |
|---|
| 406 | |
|---|
| 407 | typedef struct DecState{ |
|---|
| 408 | theora_state tstate; |
|---|
| 409 | theora_info tinfo; |
|---|
| 410 | mblk_t *yuv; |
|---|
| 411 | mblk_t *curframe; |
|---|
| 412 | bool_t ready; |
|---|
| 413 | }DecState; |
|---|
| 414 | |
|---|
| 415 | static void dec_init(MSFilter *f){ |
|---|
| 416 | DecState *s=(DecState *)ms_new(DecState,1); |
|---|
| 417 | s->ready=FALSE; |
|---|
| 418 | theora_info_init(&s->tinfo); |
|---|
| 419 | s->yuv=NULL; |
|---|
| 420 | s->curframe=NULL; |
|---|
| 421 | f->data=s; |
|---|
| 422 | } |
|---|
| 423 | |
|---|
| 424 | static void dec_uninit(MSFilter *f){ |
|---|
| 425 | DecState *s=(DecState*)f->data; |
|---|
| 426 | if (s->yuv!=NULL) freemsg(s->yuv); |
|---|
| 427 | if (s->curframe!=NULL) freemsg(s->curframe); |
|---|
| 428 | theora_info_clear(&s->tinfo); |
|---|
| 429 | ms_free(s); |
|---|
| 430 | } |
|---|
| 431 | |
|---|
| 432 | static bool_t dec_init_theora(DecState *s, ogg_packet *op){ |
|---|
| 433 | theora_comment tcom; |
|---|
| 434 | static const int ident_packet_size=42; |
|---|
| 435 | theora_comment_init(&tcom); |
|---|
| 436 | tcom.vendor="dummy"; |
|---|
| 437 | op->b_o_s=1; |
|---|
| 438 | if (theora_decode_header(&s->tinfo,&tcom,op)==0){ |
|---|
| 439 | op->packet+=ident_packet_size; |
|---|
| 440 | op->bytes-=ident_packet_size; |
|---|
| 441 | /*recall once to decode tables*/ |
|---|
| 442 | if (theora_decode_header(&s->tinfo,&tcom,op)==0){ |
|---|
| 443 | if (theora_decode_init(&s->tstate,&s->tinfo)==0){ |
|---|
| 444 | ms_debug("theora decoder ready, pixfmt=%i", |
|---|
| 445 | s->tinfo.pixelformat); |
|---|
| 446 | return TRUE; |
|---|
| 447 | } |
|---|
| 448 | }else{ |
|---|
| 449 | ms_warning("error decoding theora tables"); |
|---|
| 450 | } |
|---|
| 451 | }else{ |
|---|
| 452 | ms_warning("error decoding theora header"); |
|---|
| 453 | } |
|---|
| 454 | return FALSE; |
|---|
| 455 | } |
|---|
| 456 | /* remove payload header and agregates fragmented packets */ |
|---|
| 457 | static mblk_t *dec_unpacketize(MSFilter *f, DecState *s, mblk_t *im, int *tdt){ |
|---|
| 458 | uint8_t ft; |
|---|
| 459 | *tdt=payload_header_get_tdt((uint8_t*)im->b_rptr); |
|---|
| 460 | ft=payload_header_get_ft((uint8_t*)im->b_rptr); |
|---|
| 461 | im->b_rptr+=6; |
|---|
| 462 | |
|---|
| 463 | if (ft==NOT_FRAGMENTED) return im; |
|---|
| 464 | if (ft==START_FRAGMENT){ |
|---|
| 465 | if (s->curframe!=NULL) |
|---|
| 466 | freemsg(s->curframe); |
|---|
| 467 | s->curframe=im; |
|---|
| 468 | }else if (ft==CONT_FRAGMENT){ |
|---|
| 469 | if (s->curframe!=NULL) |
|---|
| 470 | concatb(s->curframe,im); |
|---|
| 471 | else |
|---|
| 472 | freemsg(im); |
|---|
| 473 | }else{/*end fragment*/ |
|---|
| 474 | if (s->curframe!=NULL){ |
|---|
| 475 | mblk_t *ret; |
|---|
| 476 | concatb(s->curframe,im); |
|---|
| 477 | msgpullup(s->curframe,-1); |
|---|
| 478 | ret=s->curframe; |
|---|
| 479 | s->curframe=NULL; |
|---|
| 480 | return ret; |
|---|
| 481 | }else |
|---|
| 482 | freemsg(im); |
|---|
| 483 | } |
|---|
| 484 | return NULL; |
|---|
| 485 | } |
|---|
| 486 | |
|---|
| 487 | static void dec_process_frame(MSFilter *f, DecState *s, ogg_packet *op){ |
|---|
| 488 | yuv_buffer yuv; |
|---|
| 489 | if (theora_decode_packetin(&s->tstate,op)==0){ |
|---|
| 490 | if (theora_decode_YUVout(&s->tstate,&yuv)==0){ |
|---|
| 491 | mblk_t *om; |
|---|
| 492 | int i; |
|---|
| 493 | int ylen=yuv.y_width*yuv.y_height; |
|---|
| 494 | int uvlen=yuv.uv_width*yuv.uv_height; |
|---|
| 495 | ms_debug("Got yuv buffer from theora decoder"); |
|---|
| 496 | if (s->yuv==NULL){ |
|---|
| 497 | int len=(ylen)+(2*uvlen); |
|---|
| 498 | s->yuv=allocb(len,0); |
|---|
| 499 | } |
|---|
| 500 | om=dupb(s->yuv); |
|---|
| 501 | for(i=0;i<yuv.y_height;++i){ |
|---|
| 502 | memcpy(om->b_wptr,yuv.y+yuv.y_stride*i,yuv.y_width); |
|---|
| 503 | om->b_wptr+=yuv.y_width; |
|---|
| 504 | } |
|---|
| 505 | for(i=0;i<yuv.uv_height;++i){ |
|---|
| 506 | memcpy(om->b_wptr,yuv.u+yuv.uv_stride*i,yuv.uv_width); |
|---|
| 507 | om->b_wptr+=yuv.uv_width; |
|---|
| 508 | } |
|---|
| 509 | for(i=0;i<yuv.uv_height;++i){ |
|---|
| 510 | memcpy(om->b_wptr,yuv.v+yuv.uv_stride*i,yuv.uv_width); |
|---|
| 511 | om->b_wptr+=yuv.uv_width; |
|---|
| 512 | } |
|---|
| 513 | ms_queue_put(f->outputs[0],om); |
|---|
| 514 | } |
|---|
| 515 | }else{ |
|---|
| 516 | ms_warning("theora decoding error"); |
|---|
| 517 | } |
|---|
| 518 | } |
|---|
| 519 | |
|---|
| 520 | static void dec_process(MSFilter *f){ |
|---|
| 521 | mblk_t *im; |
|---|
| 522 | mblk_t *m; |
|---|
| 523 | ogg_packet op; |
|---|
| 524 | int tdt; |
|---|
| 525 | DecState *s=(DecState*)f->data; |
|---|
| 526 | while( (im=ms_queue_get(f->inputs[0]))!=0) { |
|---|
| 527 | m=dec_unpacketize(f,s,im,&tdt); |
|---|
| 528 | if (m!=NULL){ |
|---|
| 529 | /* now in im we have only the theora data*/ |
|---|
| 530 | op.packet=(uint8_t*)m->b_rptr; |
|---|
| 531 | op.bytes=m->b_wptr-m->b_rptr; |
|---|
| 532 | op.b_o_s=0; |
|---|
| 533 | op.e_o_s=0; |
|---|
| 534 | op.granulepos=0; |
|---|
| 535 | op.packetno=0; |
|---|
| 536 | if (tdt!=THEORA_RAW_DATA) /*packed conf*/ { |
|---|
| 537 | if (!s->ready){ |
|---|
| 538 | if (dec_init_theora(s,&op)) |
|---|
| 539 | s->ready=TRUE; |
|---|
| 540 | } |
|---|
| 541 | }else{ |
|---|
| 542 | if (s->ready){ |
|---|
| 543 | dec_process_frame(f,s,&op); |
|---|
| 544 | }else{ |
|---|
| 545 | ms_warning("skipping theora packet because decoder was not initialized yet with theora header and tables"); |
|---|
| 546 | } |
|---|
| 547 | } |
|---|
| 548 | freemsg(m); |
|---|
| 549 | } |
|---|
| 550 | } |
|---|
| 551 | } |
|---|
| 552 | |
|---|
| 553 | #ifdef _MSC_VER |
|---|
| 554 | |
|---|
| 555 | MSFilterDesc ms_theora_dec_desc={ |
|---|
| 556 | MS_THEORA_DEC_ID, |
|---|
| 557 | "MSTheoraDec", |
|---|
| 558 | N_("The theora video decoder from xiph.org"), |
|---|
| 559 | MS_FILTER_DECODER, |
|---|
| 560 | "theora", |
|---|
| 561 | 1, |
|---|
| 562 | 1, |
|---|
| 563 | dec_init, |
|---|
| 564 | NULL, |
|---|
| 565 | dec_process, |
|---|
| 566 | NULL, |
|---|
| 567 | dec_uninit, |
|---|
| 568 | NULL |
|---|
| 569 | }; |
|---|
| 570 | |
|---|
| 571 | #else |
|---|
| 572 | |
|---|
| 573 | MSFilterDesc ms_theora_dec_desc={ |
|---|
| 574 | .id=MS_THEORA_DEC_ID, |
|---|
| 575 | .name="MSTheoraDec", |
|---|
| 576 | .text=N_("The theora video decoder from xiph.org"), |
|---|
| 577 | .category=MS_FILTER_DECODER, |
|---|
| 578 | .enc_fmt="theora", |
|---|
| 579 | .ninputs=1, |
|---|
| 580 | .noutputs=1, |
|---|
| 581 | .init=dec_init, |
|---|
| 582 | .process=dec_process, |
|---|
| 583 | .uninit=dec_uninit |
|---|
| 584 | }; |
|---|
| 585 | |
|---|
| 586 | #endif |
|---|
| 587 | MS_FILTER_DESC_EXPORT(ms_theora_dec_desc) |
|---|