📄 idirectfbvideoprovider_openquicktime.c
字号:
WriteYUVFrame( IDirectFBVideoProvider_OpenQuicktime_data *data ){ __u16 *dst; unsigned int pitch; CoreSurface *surface; IDirectFBSurface_data *dst_data; __u8 *src_y, *src_u, *src_v; __u8 *dst_y, *dst_u, *dst_v; int x, y, off_x, off_y; dst_data = (IDirectFBSurface_data*) data->destination->priv; surface = dst_data->surface; dfb_surface_soft_lock( surface, DSLF_WRITE, (void**)&dst, &pitch, 0 ); src_y = data->yuv.lines[0]; src_u = data->yuv.lines[1]; src_v = data->yuv.lines[2]; off_x = data->dest_clip.x - data->dest_rect.x; off_y = data->dest_clip.y - data->dest_rect.y; src_y += off_y * data->video.width + off_x; src_u += (off_y / 2) * (data->video.width / 2) + off_x / 2; src_v += (off_y / 2) * (data->video.width / 2) + off_x / 2; /* this code might not work with offsets not being a multiple of 2 */ switch (surface->format) { case DSPF_I420: case DSPF_YV12: dst_y = (__u8*) dst; dst_y += data->dest_clip.y * pitch + data->dest_clip.x; if (surface->format == DSPF_I420) { dst_u = (__u8*) dst + pitch * data->video.height; dst_v = dst_u + pitch/2 * data->video.height / 2; dst_u += data->dest_clip.y/2 * pitch/2 + data->dest_clip.x/2; dst_v += data->dest_clip.y/2 * pitch/2 + data->dest_clip.x/2; } else { dst_v = (__u8*) dst + pitch * data->video.height; dst_u = dst_v + pitch/2 * data->video.height / 2; dst_u += data->dest_clip.y/2 * pitch/2 + data->dest_clip.x/2; dst_v += data->dest_clip.y/2 * pitch/2 + data->dest_clip.x/2; } for (y=0; y<data->dest_clip.h; y++) { dfb_memcpy( dst_y, src_y, data->dest_clip.w ); src_y += data->video.width; dst_y += pitch; if (y & 1) { src_u += data->video.width/2; src_v += data->video.width/2; dst_u += pitch/2; dst_v += pitch/2; } else { dfb_memcpy( dst_u, src_u, data->dest_clip.w/2 ); dfb_memcpy( dst_v, src_v, data->dest_clip.w/2 ); } } break; case DSPF_YUY2: dst += data->dest_clip.y * pitch + data->dest_clip.x; for (y=0; y<data->dest_clip.h; y++) { for (x=0; x<data->dest_clip.w; x++) { if (x & 1) dst[x] = (src_v[x/2] << 8) | src_y[x]; else dst[x] = (src_u[x/2] << 8) | src_y[x]; } src_y += data->video.width; if (y & 1) { src_u += data->video.width/2; src_v += data->video.width/2; } dst += pitch/2; } break; case DSPF_UYVY: dst += data->dest_clip.y * pitch + data->dest_clip.x; for (y=0; y<data->dest_clip.h; y++) { for (x=0; x<data->dest_clip.w; x++) { if (x & 1) dst[x] = (src_y[x] << 8) | src_v[x/2]; else dst[x] = (src_y[x] << 8) | src_u[x/2]; } src_y += data->video.width; if (y & 1) { src_u += data->video.width/2; src_v += data->video.width/2; } dst += pitch/2; } break; default: break; } dfb_surface_unlock( dst_data->surface, 0 );}static void*VideoThread( void *ctx ){ IDirectFBVideoProvider_OpenQuicktime_data *data = (IDirectFBVideoProvider_OpenQuicktime_data*) ctx; struct timeval start, after; long frame_delay; long delay = -1; double rate; int drop = 0; long frame, start_frame = 0; long frames; rate = data->video.rate / 1000.0; frame_delay = (long) (1000 / data->video.rate); frames = data->video.length; if (frames == 1) frames = -1; data->video.seeked = 1; while (data->video.playing) { pthread_mutex_lock( &data->video.lock ); if (!data->video.playing) { pthread_mutex_unlock( &data->video.lock ); break; } if (data->video.seeked) { drop = 0; gettimeofday(&start, 0); start_frame = quicktime_video_position( data->file, 0 ); data->video.seeked = 0; } if (drop) { while (drop--) quicktime_decode_video( data->file, BC_NONE, NULL, 0 ); drop = 0; } else { int ret; if (data->video.yuv) ret = quicktime_decode_video( data->file, BC_YUV420P, data->yuv.lines, 0 ); else ret = quicktime_decode_video( data->file, BC_RGB888, data->rgb.lines, 0 ); if (ret) { pthread_mutex_unlock( &data->video.lock ); break; } if (data->video.yuv) WriteYUVFrame( data ); else WriteRGBFrame( data ); if (data->callback) data->callback (data->ctx); } frame = quicktime_video_position( data->file, 0 ); gettimeofday (&after, 0); delay = (after.tv_sec - start.tv_sec) * 1000 + (after.tv_usec - start.tv_usec) / 1000; { long cframe = (long) (delay * rate) + start_frame; if ( frame < cframe ) { drop = cframe - frame; pthread_mutex_unlock( &data->video.lock ); continue; } else if ( frame == cframe ) delay = ((long) ((frame - start_frame + 1) / rate)) - delay; else delay = frame_delay; } after.tv_sec = 0; after.tv_usec = delay * 1000; pthread_mutex_unlock( &data->video.lock ); select( 0, 0, 0, 0, &after ); /* jump to start if arrived at last frame */ if (frame == frames) { pthread_mutex_lock( &data->video.lock ); pthread_mutex_lock( &data->audio.lock ); quicktime_seek_start( data->file ); data->video.seeked = 1; data->audio.seeked = 1; pthread_mutex_unlock( &data->audio.lock ); pthread_mutex_unlock( &data->video.lock ); } } return NULL;}static void*AudioThread( void *ctx ){ IDirectFBVideoProvider_OpenQuicktime_data *data = (IDirectFBVideoProvider_OpenQuicktime_data*) ctx; __s16 buffer[data->audio.samples_per_block * data->audio.channels]; __s16 left[data->audio.samples_per_block]; __s16 right[data->audio.samples_per_block]; /* calculate audio position */ long audio_pos = (long) ((double)quicktime_video_position (data->file, 0) * (double)data->audio.rate / (double)data->video.rate); /* seek audio */ quicktime_set_audio_position( data->file, audio_pos, 0 ); data->audio.seeked = 1; while (data->audio.playing) { pthread_mutex_lock( &data->audio.lock ); if (!data->audio.playing) { pthread_mutex_unlock( &data->audio.lock ); break; } if (data->audio.seeked) { /* flush buffered audio data */ ioctl( data->audio.fd, SNDCTL_DSP_RESET, 0 ); data->audio.seeked = 0; } if (data->audio.channels == 1) { long pos = quicktime_audio_position( data->file, 0 ); /* mono */ if ((pos < 0) || (pos + data->audio.samples_per_block) >= data->audio.length || quicktime_decode_audio( data->file, buffer, NULL, data->audio.samples_per_block, 0 )) memset( buffer, 0, data->audio.block_size ); write( data->audio.fd, buffer, data->audio.block_size ); } else { long pos = quicktime_audio_position( data->file, 0 ); /* stereo */ if ((pos < 0) || (pos + data->audio.samples_per_block) >= data->audio.length || quicktime_decode_audio( data->file, left, NULL, data->audio.samples_per_block, 0 )) memset( buffer, 0, data->audio.block_size ); else { int i; quicktime_set_audio_position( data->file, pos, 0 ); quicktime_decode_audio( data->file, right, NULL, data->audio.samples_per_block, 1 ); /* produce interleaved buffer */ for (i=0; i<data->audio.samples_per_block; i++) { buffer[i*2+0] = left[i]; buffer[i*2+1] = right[i]; } } write( data->audio.fd, buffer, data->audio.block_size ); } pthread_mutex_unlock( &data->audio.lock ); } /* tell sound driver that we stopped playback */ ioctl( data->audio.fd, SNDCTL_DSP_POST, 0 ); return NULL;}static DFBResultIDirectFBVideoProvider_OpenQuicktime_PlayTo( IDirectFBVideoProvider *thiz, IDirectFBSurface *destination, DFBRectangle *dstrect, DVFrameCallback callback, void *ctx ){ int yuv_mode = 0; DFBRectangle rect, dest_rect, dest_clip; IDirectFBSurface_data *dst_data; INTERFACE_GET_DATA (IDirectFBVideoProvider_OpenQuicktime) if (!destination) return DFB_INVARG; dst_data = (IDirectFBSurface_data*)destination->priv; if (!dst_data) return DFB_DEAD; /* check if destination format is supported */ switch (dst_data->surface->format) { case DSPF_I420: case DSPF_YV12: case DSPF_YUY2: case DSPF_UYVY: if (!data->yuv.supported) return DFB_UNSUPPORTED; yuv_mode = 1; break; case DSPF_RGB332: case DSPF_RGB15: case DSPF_RGB16: case DSPF_RGB24: case DSPF_RGB32: case DSPF_ARGB: if (data->rgb.supported) break; default: return DFB_UNSUPPORTED; } /* build the destination rectangle */ if (dstrect) { if (dstrect->w < 1 || dstrect->h < 1) return DFB_INVARG; rect = *dstrect; rect.x += dst_data->area.wanted.x; rect.y += dst_data->area.wanted.y; } else rect = dst_data->area.wanted; /* check destination rect and save it */ if (rect.w != data->video.width || rect.h != data->video.height) return DFB_UNSUPPORTED; dest_rect = rect; /* build the clip rectangle */ if (!dfb_rectangle_intersect( &rect, &dst_data->area.current )) return DFB_INVARG; dest_clip = rect; pthread_mutex_lock( &data->video.lock ); /* release previous destination surface */ if (data->destination) { data->destination->Release( data->destination ); data->destination = NULL; /* FIXME: remove listener */ } /* reference destination surface */ destination->AddRef( destination ); data->destination = destination; /* FIXME: install listener */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -