qtffthread.cpp

00001 #include "qtffthread.h"
00002 #include "qtffutil.h"
00003 
00004 qtffthread::qtffthread()
00005 {
00006 }
00007 
00008 qtffthread::~qtffthread()
00009 {
00010         EXIT_INPUT_THREAD=1;
00011         wait();
00012 }
00013 
00014 void qtffthread::init(VideoState *is)
00015 {
00016         is->parse_tid = SDL_CreateThread(decode_thread, is);
00017     if (!is->parse_tid) {
00018         av_free(is);
00019         
00020     }
00021 
00022 }
00023 
00024 void qtffthread::togglePause()
00025 {
00026         //toggle_pause();
00027         // why doesnt this work?
00028         SDL_Event evt;
00029         evt.type = SDL_KEYDOWN;
00030         evt.key.keysym.sym = SDLK_SPACE;
00031         while ( SDL_PushEvent( &evt ) == -1) {}
00032 }
00033 /* schedule a video refresh in 'delay' ms */
00034 //void qtffthread::schedule_refresh(VideoState *is, int delay)
00035 //{
00036     //SDL_AddTimer(delay, sdl_refresh_timer_cb, is);
00037 //}
00038 
00039 /* handle an event sent by the GUI */
00040 void qtffthread::run()
00041 {
00042     SDL_Event event;
00043     double incr, pos, frac;
00044     while (!EXIT_INPUT_THREAD)
00045     {
00046         SDL_WaitEvent(&event);
00047         switch(event.type) {
00048             case SDL_KEYDOWN:
00049                 switch(event.key.keysym.sym) {
00050                     case SDLK_ESCAPE:
00051                     case SDLK_q:
00052                         do_exit();
00053                         break;
00054                     case SDLK_f:
00055                         toggle_full_screen();
00056                         break;
00057                     case SDLK_p:
00058                     case SDLK_SPACE:
00059                         toggle_pause();
00060                         break;
00061                         case SDLK_s: //S: Step to next frame
00062                             step_to_next_frame();
00063                             break;
00064                     case SDLK_a:
00065                         if (cur_stream)
00066                             stream_cycle_channel(cur_stream, CODEC_TYPE_AUDIO);
00067                         break;
00068                     case SDLK_v:
00069                         if (cur_stream)
00070                             stream_cycle_channel(cur_stream, CODEC_TYPE_VIDEO);
00071                         break;
00072                     case SDLK_t:
00073                         if (cur_stream)
00074                             stream_cycle_channel(cur_stream, CODEC_TYPE_SUBTITLE);
00075                         break;
00076                     case SDLK_w:
00077                         toggle_audio_display();
00078                         break;
00079                     case SDLK_LEFT:
00080                         incr = -10.0;
00081                         goto do_seek;
00082                     case SDLK_RIGHT:
00083                         incr = 10.0;
00084                         goto do_seek;
00085                     case SDLK_UP:
00086                         incr = 60.0;
00087                         goto do_seek;
00088                     case SDLK_DOWN:
00089                         incr = -60.0;
00090             do_seek:
00091                         if (cur_stream) {
00092                 pos = get_master_clock(cur_stream);
00093                 pos += incr;
00094                 stream_seek(cur_stream, (int64_t)(pos * AV_TIME_BASE), incr);
00095                         }
00096                         break;
00097                     default:
00098                         break;
00099                 }
00100                 break;
00101             case SDL_MOUSEBUTTONDOWN:
00102                 if (cur_stream) {
00103                     int ns, hh, mm, ss;
00104                     int tns, thh, tmm, tss;
00105                     tns = cur_stream->ic->duration/1000000LL;
00106                     thh = tns/3600;
00107                     tmm = (tns%3600)/60;
00108                     tss = (tns%60);
00109                     frac = (double)event.button.x/(double)cur_stream->width;
00110                     ns = frac*tns;
00111                     hh = ns/3600;
00112                     mm = (ns%3600)/60;
00113                     ss = (ns%60);
00114                     fprintf(stderr, "Seek to %2.0f%% (%2d:%02d:%02d) of total duration (%2d:%02d:%02d)       \n", frac*100,
00115                             hh, mm, ss, thh, tmm, tss);
00116                     stream_seek(cur_stream, (int64_t)(cur_stream->ic->start_time+frac*cur_stream->ic->duration), 0);
00117                 }
00118                 break;
00119             case SDL_VIDEORESIZE:
00120                 if (cur_stream) {
00121                     myscreen = SDL_SetVideoMode(event.resize.w, event.resize.h, 0,
00122                                               SDL_HWSURFACE|SDL_RESIZABLE|SDL_ASYNCBLIT|SDL_HWACCEL);
00123                     cur_stream->width = event.resize.w;
00124                     cur_stream->height = event.resize.h;
00125                 }
00126                 break;
00127             case SDL_QUIT:
00128             case FF_QUIT_EVENT:
00129                 do_exit();
00130                 break;
00131             case FF_ALLOC_EVENT:
00132                 alloc_picture(event.user.data1);
00133                 break;
00134             case FF_REFRESH_EVENT:
00135                 video_refresh_timer(event.user.data1);
00136                 break;
00137             default:
00138                 break;
00139         }
00140     }
00141 }
00142 
00143 void qtffthread::do_exit(void)
00144 {
00145         EXIT_INPUT_THREAD=1;
00146         //wait();
00147     if (cur_stream) {
00148         stream_close(cur_stream);
00149         cur_stream = NULL;
00150     }
00151     if (show_status)
00152         printf("\n");
00153     SDL_Quit();
00154     exit(0);
00155 }
00156 
00157 void qtffthread::toggle_full_screen(void)
00158 {
00159     int w, h, flags;
00160     is_full_screen = !is_full_screen;
00161     if (!fs_screen_width) {
00162         /* use default SDL method */
00163         SDL_WM_ToggleFullScreen(myscreen);
00164     } else {
00165         /* use the recorded resolution */
00166         flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL;
00167         if (is_full_screen) {
00168             w = fs_screen_width;
00169             h = fs_screen_height;
00170             flags |= SDL_FULLSCREEN;
00171         } else {
00172             w = screen_width;
00173             h = screen_height;
00174             flags |= SDL_RESIZABLE;
00175         }
00176         myscreen = SDL_SetVideoMode(w, h, 0, flags);
00177         cur_stream->width = w;
00178         cur_stream->height = h;
00179     }
00180 }
00181 
00182 void qtffthread::toggle_pause(void)
00183 {
00184     if (cur_stream)
00185         stream_pause(cur_stream);
00186     step = 0;
00187 }
00188 
00189 void qtffthread::stream_cycle_channel(VideoState *is, int codec_type)
00190 {
00191     AVFormatContext *ic = is->ic;
00192     int start_index, stream_index;
00193     AVStream *st;
00194 
00195     if (codec_type == CODEC_TYPE_VIDEO)
00196         start_index = is->video_stream;
00197     else if (codec_type == CODEC_TYPE_AUDIO)
00198         start_index = is->audio_stream;
00199     else
00200         start_index = is->subtitle_stream;
00201     if (start_index < (codec_type == CODEC_TYPE_SUBTITLE ? -1 : 0))
00202         return;
00203     stream_index = start_index;
00204     for(;;) {
00205         if (++stream_index >= is->ic->nb_streams)
00206         {
00207             if (codec_type == CODEC_TYPE_SUBTITLE)
00208             {
00209                 stream_index = -1;
00210                 goto the_end;
00211             } else
00212                 stream_index = 0;
00213         }
00214         if (stream_index == start_index)
00215             return;
00216         st = ic->streams[stream_index];
00217         if (st->codec->codec_type == codec_type) {
00218             /* check that parameters are OK */
00219             switch(codec_type) {
00220                 case CODEC_TYPE_AUDIO:
00221                     if (st->codec->sample_rate != 0 &&
00222                         st->codec->channels != 0)
00223                         goto the_end;
00224                     break;
00225                 case CODEC_TYPE_VIDEO:
00226                 case CODEC_TYPE_SUBTITLE:
00227                     goto the_end;
00228                 default:
00229                     break;
00230             }
00231         }
00232     }
00233  the_end:
00234          stream_component_close(is, start_index);
00235  stream_component_open(is, stream_index);
00236 }
00237 
00238 
00239 
00240 
00241 void qtffthread::step_to_next_frame(void)
00242 {
00243     if (cur_stream) {
00244         if (cur_stream->paused)
00245             cur_stream->paused=0;
00246         cur_stream->video_current_pts = get_video_clock(cur_stream);
00247     }
00248     step = 1;
00249 }
00250 
00251 
00252 void qtffthread::toggle_audio_display(void)
00253 {
00254     if (cur_stream) {
00255         cur_stream->show_audio = !cur_stream->show_audio;
00256     }
00257 }
00258 
00259 /* seek in the stream */
00260 void qtffthread::stream_seek(VideoState *is, int64_t pos, int rel)
00261 {
00262     if (!is->seek_req) {
00263         is->seek_pos = pos;
00264         is->seek_flags = rel < 0 ? AVSEEK_FLAG_BACKWARD : 0;
00265         is->seek_req = 1;
00266     }
00267 }
00268 
00269 /* allocate a picture (needs to do that in main thread to avoid
00270    potential locking problems */
00271  void qtffthread::alloc_picture(void *opaque)
00272 {
00273     VideoState *is = (VideoState*)opaque;
00274     VideoPicture *vp;
00275 
00276     vp = &is->pictq[is->pictq_windex];
00277 
00278     if (vp->bmp)
00279         SDL_FreeYUVOverlay(vp->bmp);
00280 
00281     vp->bmp = SDL_CreateYUVOverlay(is->video_st->codec->width,
00282                                    is->video_st->codec->height,
00283                                    SDL_YV12_OVERLAY,
00284                                    myscreen);
00285     vp->width = is->video_st->codec->width;
00286     vp->height = is->video_st->codec->height;
00287 
00288     SDL_LockMutex(is->pictq_mutex);
00289     vp->allocated = 1;
00290     SDL_CondSignal(is->pictq_cond);
00291     SDL_UnlockMutex(is->pictq_mutex);
00292 }
00293 
00294 /* called to display each frame */
00295  void qtffthread::video_refresh_timer(void *opaque)
00296 {
00297     VideoState *is = (VideoState*)opaque;
00298     VideoPicture *vp;
00299     double actual_delay, delay, sync_threshold, ref_clock, diff;
00300 
00301     SubPicture *sp, *sp2;
00302 
00303     if (is->video_st) {
00304         if (is->pictq_size == 0) {
00305             /* if no picture, need to wait */
00306             schedule_refresh(is, 1);
00307         } else {
00308             /* dequeue the picture */
00309             vp = &is->pictq[is->pictq_rindex];
00310 
00311             /* update current video pts */
00312             is->video_current_pts = vp->pts;
00313             is->video_current_pts_time = av_gettime();
00314 
00315             /* compute nominal delay */
00316             delay = vp->pts - is->frame_last_pts;
00317             if (delay <= 0 || delay >= 1.0) {
00318                 /* if incorrect delay, use previous one */
00319                 delay = is->frame_last_delay;
00320             }
00321             is->frame_last_delay = delay;
00322             is->frame_last_pts = vp->pts;
00323 
00324             /* update delay to follow master synchronisation source */
00325             if (((is->av_sync_type == AV_SYNC_AUDIO_MASTER && is->audio_st) ||
00326                   is->av_sync_type == AV_SYNC_EXTERNAL_CLOCK)) {
00327                 /* if video is slave, we try to correct big delays by
00328                 duplicating or deleting a frame */
00329                 ref_clock = get_master_clock(is);
00330                 diff = vp->pts - ref_clock;
00331 
00332                 /* skip or repeat frame. We take into account the
00333                 delay to compute the threshold. I still don't know
00334                 if it is the best guess */
00335                 sync_threshold = AV_SYNC_THRESHOLD;
00336                 if (delay > sync_threshold)
00337                     sync_threshold = delay;
00338                 if (fabs(diff) < AV_NOSYNC_THRESHOLD) {
00339                     if (diff <= -sync_threshold)
00340                         delay = 0;
00341                     else if (diff >= sync_threshold)
00342                         delay = 2 * delay;
00343                 }
00344                   }
00345 
00346                   is->frame_timer += delay;
00347             /* compute the REAL delay (we need to do that to avoid
00348                   long term errors */
00349                   actual_delay = is->frame_timer - (av_gettime() / 1000000.0);
00350                   if (actual_delay < 0.010) {
00351                       /* XXX: should skip picture */
00352                       actual_delay = 0.010;
00353                   }
00354                   /* launch timer for next picture */
00355                   schedule_refresh(is, (int)(actual_delay * 1000 + 0.5));
00356 
00357 #if defined(DEBUG_SYNC)
00358             printf("video: delay=%0.3f actual_delay=%0.3f pts=%0.3f A-V=%f\n",
00359                    delay, actual_delay, vp->pts, -diff);
00360 #endif
00361 
00362             if(is->subtitle_st) {
00363     if (is->subtitle_stream_changed) {
00364         SDL_LockMutex(is->subpq_mutex);
00365 
00366         while (is->subpq_size) {
00367             free_subpicture(&is->subpq[is->subpq_rindex]);
00368 
00369             /* update queue size and signal for next picture */
00370             if (++is->subpq_rindex == SUBPICTURE_QUEUE_SIZE)
00371                 is->subpq_rindex = 0;
00372 
00373             is->subpq_size--;
00374         }
00375         is->subtitle_stream_changed = 0;
00376 
00377         SDL_CondSignal(is->subpq_cond);
00378         SDL_UnlockMutex(is->subpq_mutex);
00379     } else {
00380         if (is->subpq_size > 0) {
00381             sp = &is->subpq[is->subpq_rindex];
00382 
00383             if (is->subpq_size > 1)
00384                 sp2 = &is->subpq[(is->subpq_rindex + 1) % SUBPICTURE_QUEUE_SIZE];
00385             else
00386                 sp2 = NULL;
00387 
00388             if ((is->video_current_pts > (sp->pts + ((float) sp->sub.end_display_time / 1000)))
00389                  || (sp2 && is->video_current_pts > (sp2->pts + ((float) sp2->sub.start_display_time / 1000))))
00390             {
00391                 free_subpicture(sp);
00392 
00393                 /* update queue size and signal for next picture */
00394                 if (++is->subpq_rindex == SUBPICTURE_QUEUE_SIZE)
00395                     is->subpq_rindex = 0;
00396 
00397                 SDL_LockMutex(is->subpq_mutex);
00398                 is->subpq_size--;
00399                 SDL_CondSignal(is->subpq_cond);
00400                 SDL_UnlockMutex(is->subpq_mutex);
00401             }
00402         }
00403     }
00404             }
00405 
00406             /* display picture */
00407             video_display(is);
00408 
00409             /* update queue size and signal for next picture */
00410             if (++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE)
00411                 is->pictq_rindex = 0;
00412 
00413             SDL_LockMutex(is->pictq_mutex);
00414             is->pictq_size--;
00415             SDL_CondSignal(is->pictq_cond);
00416             SDL_UnlockMutex(is->pictq_mutex);
00417         }
00418     } else if (is->audio_st) {
00419         /* draw the next audio frame */
00420 
00421         schedule_refresh(is, 40);
00422 
00423         /* if only audio stream, then display the audio bars (better
00424         than nothing, just to test the implementation */
00425 
00426         /* display picture */
00427         video_display(is);
00428     } else {
00429         schedule_refresh(is, 100);
00430     }
00431     if (show_status) {
00432         static int64_t last_time;
00433         int64_t cur_time;
00434         int aqsize, vqsize, sqsize;
00435         double av_diff;
00436 
00437         cur_time = av_gettime();
00438         if (!last_time || (cur_time - last_time) >= 500 * 1000) {
00439             aqsize = 0;
00440             vqsize = 0;
00441             sqsize = 0;
00442             if (is->audio_st)
00443                 aqsize = is->audioq.size;
00444             if (is->video_st)
00445                 vqsize = is->videoq.size;
00446             if (is->subtitle_st)
00447                 sqsize = is->subtitleq.size;
00448             av_diff = 0;
00449             if (is->audio_st && is->video_st)
00450                 av_diff = get_audio_clock(is) - get_video_clock(is);
00451             printf("%7.2f A-V:%7.3f aq=%5dKB vq=%5dKB sq=%5dB    \r",
00452                    get_master_clock(is), av_diff, aqsize / 1024, vqsize / 1024, sqsize);
00453             fflush(stdout);
00454             last_time = cur_time;
00455         }
00456     }
00457 }
00458 
00459 void qtffthread::free_subpicture(SubPicture *sp)
00460 {
00461     int i;
00462 
00463     for (i = 0; i < sp->sub.num_rects; i++)
00464     {
00465         av_free(sp->sub.rects[i].bitmap);
00466         av_free(sp->sub.rects[i].rgba_palette);
00467     }
00468 
00469     av_free(sp->sub.rects);
00470 
00471     memset(&sp->sub, 0, sizeof(AVSubtitle));
00472 }
00473 
00474 /* schedule a video refresh in 'delay' ms */
00475 void qtffthread::schedule_refresh(VideoState *is, int delay)
00476 {
00477     SDL_AddTimer(delay, sdl_refresh_timer_cb, is);
00478 }
00479 
00480 /* display the current picture, if any */
00481 void qtffthread::video_display(VideoState *is)
00482 {
00483     if (is->audio_st && is->show_audio)
00484         video_audio_display(is);
00485     else if (is->video_st)
00486         video_image_display(is);
00487 }
00488 void qtffthread::stream_close(VideoState *is)
00489 {
00490     VideoPicture *vp;
00491     int i;
00492     /* XXX: use a special url_shutdown call to abort parse cleanly */
00493     is->abort_request = 1;
00494     SDL_WaitThread(is->parse_tid, NULL);
00495 
00496     /* free all pictures */
00497     for(i=0;i<VIDEO_PICTURE_QUEUE_SIZE; i++) {
00498         vp = &is->pictq[i];
00499         if (vp->bmp) {
00500             SDL_FreeYUVOverlay(vp->bmp);
00501             vp->bmp = NULL;
00502         }
00503     }
00504     SDL_DestroyMutex(is->pictq_mutex);
00505     SDL_DestroyCond(is->pictq_cond);
00506     SDL_DestroyMutex(is->subpq_mutex);
00507     SDL_DestroyCond(is->subpq_cond);
00508     SDL_DestroyMutex(is->subtitle_decoder_mutex);
00509     SDL_DestroyMutex(is->audio_decoder_mutex);
00510     SDL_DestroyMutex(is->video_decoder_mutex);
00511 }
00512 
00513 void qtffthread::video_audio_display(VideoState *s)
00514 {
00515     int i, i_start, x, y1, y, ys, delay, n, nb_display_channels;
00516     int ch, channels, h, h2, bgcolor, fgcolor;
00517     int16_t time_diff;
00518 
00519     /* compute display index : center on currently output samples */
00520     channels = s->audio_st->codec->channels;
00521     nb_display_channels = channels;
00522     if (!s->paused) {
00523         n = 2 * channels;
00524         delay = audio_write_get_buf_size(s);
00525         delay /= n;
00526 
00527         /* to be more precise, we take into account the time spent since
00528         the last buffer computation */
00529         if (audio_callback_time) {
00530             time_diff = av_gettime() - audio_callback_time;
00531             delay += (time_diff * s->audio_st->codec->sample_rate) / 1000000;
00532         }
00533 
00534         delay -= s->width / 2;
00535         if (delay < s->width)
00536             delay = s->width;
00537         i_start = compute_mod(s->sample_array_index - delay * channels, SAMPLE_ARRAY_SIZE);
00538         s->last_i_start = i_start;
00539     } else {
00540         i_start = s->last_i_start;
00541     }
00542 
00543     bgcolor = SDL_MapRGB(myscreen->format, 0x00, 0x00, 0x00);
00544     fill_rectangle(myscreen,
00545                    s->xleft, s->ytop, s->width, s->height,
00546                    bgcolor);
00547 
00548     fgcolor = SDL_MapRGB(myscreen->format, 0xff, 0xff, 0xff);
00549 
00550     /* total height for one channel */
00551     h = s->height / nb_display_channels;
00552     /* graph height / 2 */
00553     h2 = (h * 9) / 20;
00554     for(ch = 0;ch < nb_display_channels; ch++) {
00555         i = i_start + ch;
00556         y1 = s->ytop + ch * h + (h / 2); /* position of center line */
00557         for(x = 0; x < s->width; x++) {
00558             y = (s->sample_array[i] * h2) >> 15;
00559             if (y < 0) {
00560                 y = -y;
00561                 ys = y1 - y;
00562             } else {
00563                 ys = y1;
00564             }
00565             fill_rectangle(myscreen,
00566                            s->xleft + x, ys, 1, y,
00567                            fgcolor);
00568             i += channels;
00569             if (i >= SAMPLE_ARRAY_SIZE)
00570                 i -= SAMPLE_ARRAY_SIZE;
00571         }
00572     }
00573 
00574     fgcolor = SDL_MapRGB(myscreen->format, 0x00, 0x00, 0xff);
00575 
00576     for(ch = 1;ch < nb_display_channels; ch++) {
00577         y = s->ytop + ch * h;
00578         fill_rectangle(myscreen,
00579                        s->xleft, y, s->width, 1,
00580                        fgcolor);
00581     }
00582     SDL_UpdateRect(myscreen, s->xleft, s->ytop, s->width, s->height);
00583 }
00584 
00585 void qtffthread::video_image_display(VideoState *is)
00586 {
00587     VideoPicture *vp;
00588     SubPicture *sp;
00589     AVPicture pict;
00590     float aspect_ratio;
00591     int width, height, x, y;
00592     SDL_Rect rect;
00593     int i;
00594 
00595     vp = &is->pictq[is->pictq_rindex];
00596     if (vp->bmp) {
00597         /* XXX: use variable in the frame */
00598         if (is->video_st->codec->sample_aspect_ratio.num == 0)
00599             aspect_ratio = 0;
00600         else
00601             aspect_ratio = av_q2d(is->video_st->codec->sample_aspect_ratio)
00602                     * is->video_st->codec->width / is->video_st->codec->height;;
00603         if (aspect_ratio <= 0.0)
00604             aspect_ratio = (float)is->video_st->codec->width /
00605                     (float)is->video_st->codec->height;
00606         /* if an active format is indicated, then it overrides the
00607         mpeg format */
00608         
00609 if (is->subtitle_st)
00610 {
00611     if (is->subpq_size > 0)
00612     {
00613         sp = &is->subpq[is->subpq_rindex];
00614 
00615         if (vp->pts >= sp->pts + ((float) sp->sub.start_display_time / 1000))
00616         {
00617             SDL_LockYUVOverlay (vp->bmp);
00618 
00619             pict.data[0] = vp->bmp->pixels[0];
00620             pict.data[1] = vp->bmp->pixels[2];
00621             pict.data[2] = vp->bmp->pixels[1];
00622 
00623             pict.linesize[0] = vp->bmp->pitches[0];
00624             pict.linesize[1] = vp->bmp->pitches[2];
00625             pict.linesize[2] = vp->bmp->pitches[1];
00626 
00627             for (i = 0; i < sp->sub.num_rects; i++)
00628                 blend_subrect(&pict, &sp->sub.rects[i]);
00629 
00630             SDL_UnlockYUVOverlay (vp->bmp);
00631         }
00632     }
00633 }
00634 
00635 
00636         /* XXX: we suppose the myscreen has a 1.0 pixel ratio */
00637         height = is->height;
00638         width = ((int)rint(height * aspect_ratio)) & -3;
00639         if (width > is->width) {
00640             width = is->width;
00641             height = ((int)rint(width / aspect_ratio)) & -3;
00642         }
00643         x = (is->width - width) / 2;
00644         y = (is->height - height) / 2;
00645         if (!is->no_background) {
00646             /* fill the background */
00647             //            fill_border(is, x, y, width, height, QERGB(0x00, 0x00, 0x00));
00648         } else {
00649             is->no_background = 0;
00650         }
00651         rect.x = is->xleft + x;
00652         rect.y = is->xleft + y;
00653         rect.w = width;
00654         rect.h = height;
00655         SDL_DisplayYUVOverlay(vp->bmp, &rect);
00656     } else {
00657 
00658     }
00659 }
00660 
00661 void qtffthread::blend_subrect(AVPicture *dst, const AVSubtitleRect *rect)
00662 {
00663     int wrap, wrap3, width2, skip2;
00664     int y, u, v, a, u1, v1, a1, w, h;
00665     uint8_t *lum, *cb, *cr;
00666     const uint8_t *p;
00667     const uint32_t *pal;
00668 
00669     lum = dst->data[0] + rect->y * dst->linesize[0];
00670     cb = dst->data[1] + (rect->y >> 1) * dst->linesize[1];
00671     cr = dst->data[2] + (rect->y >> 1) * dst->linesize[2];
00672 
00673     width2 = (rect->w + 1) >> 1;
00674     skip2 = rect->x >> 1;
00675     wrap = dst->linesize[0];
00676     wrap3 = rect->linesize;
00677     p = rect->bitmap;
00678     pal = rect->rgba_palette;  /* Now in YCrCb! */
00679 
00680     if (rect->y & 1) {
00681         lum += rect->x;
00682         cb += skip2;
00683         cr += skip2;
00684 
00685         if (rect->x & 1) {
00686             YUVA_IN(y, u, v, a, p, pal);
00687             lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
00688             cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0);
00689             cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0);
00690             cb++;
00691             cr++;
00692             lum++;
00693             p += BPP;
00694         }
00695         for(w = rect->w - (rect->x & 1); w >= 2; w -= 2) {
00696             YUVA_IN(y, u, v, a, p, pal);
00697             u1 = u;
00698             v1 = v;
00699             a1 = a;
00700             lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
00701 
00702             YUVA_IN(y, u, v, a, p + BPP, pal);
00703             u1 += u;
00704             v1 += v;
00705             a1 += a;
00706             lum[1] = ALPHA_BLEND(a, lum[1], y, 0);
00707             cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u1, 1);
00708             cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v1, 1);
00709             cb++;
00710             cr++;
00711             p += 2 * BPP;
00712             lum += 2;
00713         }
00714         if (w) {
00715             YUVA_IN(y, u, v, a, p, pal);
00716             lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
00717             cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0);
00718             cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0);
00719         }
00720         p += wrap3 + (wrap3 - rect->w * BPP);
00721         lum += wrap + (wrap - rect->w - rect->x);
00722         cb += dst->linesize[1] - width2 - skip2;
00723         cr += dst->linesize[2] - width2 - skip2;
00724     }
00725     for(h = rect->h - (rect->y & 1); h >= 2; h -= 2) {
00726         lum += rect->x;
00727         cb += skip2;
00728         cr += skip2;
00729 
00730         if (rect->x & 1) {
00731             YUVA_IN(y, u, v, a, p, pal);
00732             u1 = u;
00733             v1 = v;
00734             a1 = a;
00735             lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
00736             p += wrap3;
00737             lum += wrap;
00738             YUVA_IN(y, u, v, a, p, pal);
00739             u1 += u;
00740             v1 += v;
00741             a1 += a;
00742             lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
00743             cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u1, 1);
00744             cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v1, 1);
00745             cb++;
00746             cr++;
00747             p += -wrap3 + BPP;
00748             lum += -wrap + 1;
00749         }
00750         for(w = rect->w - (rect->x & 1); w >= 2; w -= 2) {
00751             YUVA_IN(y, u, v, a, p, pal);
00752             u1 = u;
00753             v1 = v;
00754             a1 = a;
00755             lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
00756 
00757             YUVA_IN(y, u, v, a, p, pal);
00758             u1 += u;
00759             v1 += v;
00760             a1 += a;
00761             lum[1] = ALPHA_BLEND(a, lum[1], y, 0);
00762             p += wrap3;
00763             lum += wrap;
00764 
00765             YUVA_IN(y, u, v, a, p, pal);
00766             u1 += u;
00767             v1 += v;
00768             a1 += a;
00769             lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
00770 
00771             YUVA_IN(y, u, v, a, p, pal);
00772             u1 += u;
00773             v1 += v;
00774             a1 += a;
00775             lum[1] = ALPHA_BLEND(a, lum[1], y, 0);
00776 
00777             cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u1, 2);
00778             cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v1, 2);
00779 
00780             cb++;
00781             cr++;
00782             p += -wrap3 + 2 * BPP;
00783             lum += -wrap + 2;
00784         }
00785         if (w) {
00786             YUVA_IN(y, u, v, a, p, pal);
00787             u1 = u;
00788             v1 = v;
00789             a1 = a;
00790             lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
00791             p += wrap3;
00792             lum += wrap;
00793             YUVA_IN(y, u, v, a, p, pal);
00794             u1 += u;
00795             v1 += v;
00796             a1 += a;
00797             lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
00798             cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u1, 1);
00799             cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v1, 1);
00800             cb++;
00801             cr++;
00802             p += -wrap3 + BPP;
00803             lum += -wrap + 1;
00804         }
00805         p += wrap3 + (wrap3 - rect->w * BPP);
00806         lum += wrap + (wrap - rect->w - rect->x);
00807         cb += dst->linesize[1] - width2 - skip2;
00808         cr += dst->linesize[2] - width2 - skip2;
00809     }
00810     /* handle odd height */
00811     if (h) {
00812         lum += rect->x;
00813         cb += skip2;
00814         cr += skip2;
00815 
00816         if (rect->x & 1) {
00817             YUVA_IN(y, u, v, a, p, pal);
00818             lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
00819             cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0);
00820             cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0);
00821             cb++;
00822             cr++;
00823             lum++;
00824             p += BPP;
00825         }
00826         for(w = rect->w - (rect->x & 1); w >= 2; w -= 2) {
00827             YUVA_IN(y, u, v, a, p, pal);
00828             u1 = u;
00829             v1 = v;
00830             a1 = a;
00831             lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
00832 
00833             YUVA_IN(y, u, v, a, p + BPP, pal);
00834             u1 += u;
00835             v1 += v;
00836             a1 += a;
00837             lum[1] = ALPHA_BLEND(a, lum[1], y, 0);
00838             cb[0] = ALPHA_BLEND(a1 >> 2, cb[0], u, 1);
00839             cr[0] = ALPHA_BLEND(a1 >> 2, cr[0], v, 1);
00840             cb++;
00841             cr++;
00842             p += 2 * BPP;
00843             lum += 2;
00844         }
00845         if (w) {
00846             YUVA_IN(y, u, v, a, p, pal);
00847             lum[0] = ALPHA_BLEND(a, lum[0], y, 0);
00848             cb[0] = ALPHA_BLEND(a >> 2, cb[0], u, 0);
00849             cr[0] = ALPHA_BLEND(a >> 2, cr[0], v, 0);
00850         }
00851     }
00852 }
00853 
00854 inline int qtffthread::compute_mod(int a, int b)
00855 {
00856     a = a % b;
00857     if (a >= 0)
00858         return a;
00859     else
00860         return a + b;
00861 }
00862 
00863 inline void qtffthread::fill_rectangle(SDL_Surface *myscreen,
00864                                  int x, int y, int w, int h, int color)
00865 {
00866     SDL_Rect rect;
00867     rect.x = x;
00868     rect.y = y;
00869     rect.w = w;
00870     rect.h = h;
00871     SDL_FillRect(myscreen, &rect, color);
00872 }

Generated on Thu Aug 17 12:14:56 2006 for VisualODF by  doxygen 1.4.7