📄 read-dv.c
字号:
/* gcc 2.95.x doesn't compile some c99 constructs ... */#if __GNUC__ >= 3#include "config.h"#include <stdlib.h>#include <stdio.h>#include <string.h>#include <pthread.h>#include <fcntl.h>#include <errno.h>#include <unistd.h>#include <inttypes.h>#include <sys/mman.h>#include <libdv/dv.h>#include "grab-ng.h"/* ----------------------------------------------------------------------- */struct dv_handle { /* handles */ int fd; dv_decoder_t *dec; /* mmap()ed data */ unsigned char *map_start; unsigned char *map_ptr; off_t map_size; int map_frame; /* format */ struct ng_video_fmt vfmt; struct ng_audio_fmt afmt; /* misc video */ int rate,vframe,frames; /* misc audio */ int aframe,samples; int16_t *audiobuf[4];};/* ----------------------------------------------------------------------- */static enum color_space_e fmtid_to_colorspace[VIDEO_FMT_COUNT] = { [ 0 ... VIDEO_FMT_COUNT-1 ] = UNSET, [ VIDEO_YUYV ] = e_dv_color_yuv, [ VIDEO_RGB24 ] = e_dv_color_rgb, [ VIDEO_BGR32 ] = e_dv_color_bgr0,};/* ----------------------------------------------------------------------- */static void dv_unmap(struct dv_handle *h){ if (!h->map_ptr) return; munmap(h->map_start,h->map_size); h->map_ptr = NULL;}static void dv_map(struct dv_handle *h, int frame){ off_t map_offset; off_t pgsize, size, offset; size = h->dec->frame_size; if (0 == size) size = 120000; /* NTSC frame size */ offset = frame * size; pgsize = getpagesize(); map_offset = offset & ~(pgsize-1); h->map_size = offset - map_offset + size; h->map_start = mmap(0, h->map_size, PROT_READ, MAP_SHARED, h->fd, map_offset); if (MAP_FAILED == h->map_start) { perror("mmap"); exit(1); } h->map_ptr = h->map_start + (offset - map_offset);}static void dv_fmt(struct dv_handle *h, int *vfmt, int vn){ off_t len; int i; /* video format */ for (i = 0; i < vn; i++) { if (ng_debug) fprintf(stderr,"dv: trying: %d [%s]\n", vfmt[i],ng_vfmt_to_desc[vfmt[i]]); if (UNSET == fmtid_to_colorspace[vfmt[i]]) continue; h->vfmt.fmtid = vfmt[i]; break; } h->vfmt.width = h->dec->width; h->vfmt.height = h->dec->height; h->vfmt.bytesperline = (h->vfmt.width*ng_vfmt_to_depth[h->vfmt.fmtid]) >> 3; h->rate = (e_dv_system_625_50 == h->dec->system) ? 25 : 30; /* audio fmt */ if (1 == h->dec->audio->num_channels || 2 == h->dec->audio->num_channels) { h->afmt.fmtid = (16 == h->dec->audio->quantization) ? AUDIO_S16_NATIVE_MONO : AUDIO_U8_MONO; if (2 == h->dec->audio->num_channels) h->afmt.fmtid++; } h->afmt.rate = h->dec->audio->frequency; /* movie length (# of frames) */ len = lseek(h->fd,0,SEEK_END); h->frames = len / h->dec->frame_size; if (ng_debug) { fprintf(stderr,"dv: len=%lld => %d frames [%" PRId64 "]\n",len,h->frames, len - (off_t)h->frames * h->dec->frame_size); fprintf(stderr, "dv: quality=%d system=%d std=%d sampling=%d num_dif_seqs=%d\n" "dv: height=%d width=%d frame_size=%ld\n", h->dec->quality, h->dec->system, h->dec->std, h->dec->sampling, h->dec->num_dif_seqs, h->dec->height, h->dec->width, h->dec->frame_size); fprintf(stderr, "dv: audio: %d Hz, %d bits, %d channels," " emphasis %s\n", h->dec->audio->frequency, h->dec->audio->quantization, h->dec->audio->num_channels, (h->dec->audio->emphasis ? "on" : "off")); }}/* ----------------------------------------------------------------------- */static void* dv_open(char *moviename){ struct dv_handle *h; if (NULL == (h = malloc(sizeof(*h)))) goto oops; memset(h,0,sizeof(*h)); h->map_frame = -1; if (-1 == (h->fd = open(moviename,O_RDONLY))) { fprintf(stderr,"dv: open %s: %s\n",moviename,strerror(errno)); goto oops; } if (NULL == (h->dec = dv_decoder_new(0,0,0))) { fprintf(stderr,"dv: dv_decoder_new failed\n"); goto oops; } h->dec->quality = 3; dv_map(h, 0); if (dv_parse_header(h->dec, h->map_ptr) < 0) { fprintf(stderr,"dv: dv_parse_header failed\n"); goto oops; } dv_fmt(h,NULL,0); return h; oops: if (h->dec) dv_decoder_free(h->dec); if (-1 != h->fd) close(h->fd); if (h) free(h); return NULL;}static struct ng_video_fmt* dv_vfmt(void *handle, int *vfmt, int vn){ struct dv_handle *h = handle; dv_fmt(h,vfmt,vn); return &h->vfmt;}static struct ng_audio_fmt* dv_afmt(void *handle){ struct dv_handle *h = handle; return h->afmt.fmtid ? &h->afmt : NULL;}static struct ng_video_buf* dv_vdata(void *handle, unsigned int drop){ struct dv_handle *h = handle; struct ng_video_buf *buf; unsigned char *pixels[3]; int pitches[3]; h->vframe += drop; if (h->vframe >= h->frames) return NULL; if (ng_debug > 1) fprintf(stderr,"dv: frame %d [drop=%d]\n",h->vframe,drop); dv_unmap(h); dv_map(h, h->vframe); if (dv_parse_header(h->dec, h->map_ptr) < 0) { fprintf(stderr,"dv: dv_parse_header failed\n"); return NULL; } buf = ng_malloc_video_buf(&h->vfmt,h->vfmt.bytesperline*h->vfmt.height); switch (h->vfmt.fmtid) { case VIDEO_YUYV: pixels[0] = buf->data; pitches[0] = buf->fmt.width*2; break; case VIDEO_RGB24: pixels[0] = buf->data; pitches[0] = buf->fmt.width*3; break; case VIDEO_BGR32: pixels[0] = buf->data; pitches[0] = buf->fmt.width*4; break; default: BUG_ON(1,"unknown fmtid"); } dv_parse_packs(h->dec, h->map_ptr); dv_decode_full_frame(h->dec, h->map_ptr, fmtid_to_colorspace[h->vfmt.fmtid], pixels, pitches); buf->info.seq = h->vframe; buf->info.ts = (long long) buf->info.seq * 1000000000 / h->rate; h->vframe++; return buf;}static struct ng_audio_buf* dv_adata(void *handle){ struct dv_handle *h = handle; struct ng_audio_buf *buf; int16_t *dest; int asize, i; if (h->aframe >= h->frames) return NULL; dv_unmap(h); dv_map(h, h->aframe); if (dv_parse_header(h->dec, h->map_ptr) < 0) { fprintf(stderr,"dv: dv_parse_header failed\n"); return NULL; } asize = h->dec->audio->samples_this_frame * h->dec->audio->num_channels * h->dec->audio->quantization >> 3; if (ng_debug > 1) fprintf(stderr,"dv: audio %d [samples=%d]\n",h->aframe, h->dec->audio->samples_this_frame); buf = ng_malloc_audio_buf(&h->afmt, asize); dest = (int16_t*)buf->data; if (2 == h->dec->audio->num_channels) { if (NULL == h->audiobuf[0]) for (i = 0; i < 4; i++) h->audiobuf[i] = malloc(DV_AUDIO_MAX_SAMPLES*sizeof(int16_t)); dv_decode_full_audio(h->dec, h->map_ptr, h->audiobuf); for (i = 0; i < h->dec->audio->samples_this_frame; i++) { dest[2*i+0] = h->audiobuf[0][i]; dest[2*i+1] = h->audiobuf[1][i]; } } if (1 == h->dec->audio->num_channels) dv_decode_full_audio(h->dec, h->map_ptr, &dest); buf->info.ts = (long long) h->samples * 1000000000 / h->afmt.rate; h->samples += h->dec->audio->samples_this_frame; h->aframe++; return buf;}static int64_t dv_frame_time(void *handle){ struct dv_handle *h = handle; return 1000000000 / h->rate;}static int dv_close(void *handle){ struct dv_handle *h = handle; int i; for (i = 0; i < 4; i++) if (h->audiobuf[i]) free(h->audiobuf[i]); dv_unmap(h); dv_decoder_free(h->dec); close(h->fd); free(h); return 0;}/* ----------------------------------------------------------------------- */struct ng_reader dv_reader = { name: "dv", desc: "Digital Video", magic: { "\x1f\x07\x00", "\x3f\x07\x00" }, moff: { 0, 0x50 }, mlen: { 3, 3 }, rd_open: dv_open, rd_vfmt: dv_vfmt, rd_afmt: dv_afmt, rd_vdata: dv_vdata, rd_adata: dv_adata, frame_time: dv_frame_time, rd_close: dv_close,};extern void ng_plugin_init(void);void ng_plugin_init(void){ ng_reader_register(NG_PLUGIN_MAGIC,__FILE__,&dv_reader);}#else /* gcc3 */extern void ng_plugin_init(void);void ng_plugin_init(void) {}#endif /* gcc3 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -