📄 write-qt.c
字号:
#include "config.h"#include <stdlib.h>#include <stdio.h>#include <string.h>#include <pthread.h>#include <quicktime/quicktime.h>#include <quicktime/colormodels.h>#include <quicktime/lqt.h>#include "grab-ng.h"/* ----------------------------------------------------------------------- */struct qt_video_priv { char fcc[5]; int yuvsign; int libencode; int cmodel;};struct qt_audio_priv { char fcc[5]; int libencode;};struct qt_handle { /* libquicktime handle */ quicktime_t *fh; /* format */ struct ng_video_fmt video; struct ng_audio_fmt audio; /* misc */ int lib_video; int lib_audio; int yuvsign; int audio_sample; unsigned char **rows; unsigned char *data;};/* ----------------------------------------------------------------------- */static void*qt_open(char *filename, char *dummy, struct ng_video_fmt *video, const void *priv_video, int fps, struct ng_audio_fmt *audio, const void *priv_audio){ const struct qt_video_priv *pvideo = priv_video; const struct qt_audio_priv *paudio = priv_audio; struct qt_handle *h; if (NULL == (h = malloc(sizeof(*h)))) return NULL; memset(h,0,sizeof(*h)); h->video = *video; h->audio = *audio; if (h->video.fmtid != VIDEO_NONE) { h->lib_video = pvideo->libencode; h->yuvsign = pvideo->yuvsign; } if (h->audio.fmtid != AUDIO_NONE) h->lib_audio = paudio->libencode; if (NULL == (h->fh = quicktime_open(filename,0,1))) { fprintf(stderr,"quicktime_open failed (%s)\n",filename); goto fail; } if (h->lib_video) if (NULL == (h->rows = malloc(h->video.height * sizeof(char*)))) goto fail; if (h->yuvsign) if (NULL == (h->data = malloc(h->video.height * h->video.width * 2))) goto fail; if (h->audio.fmtid != AUDIO_NONE) { quicktime_set_audio(h->fh, ng_afmt_to_channels[h->audio.fmtid], h->audio.rate, ng_afmt_to_bits[h->audio.fmtid], (char*)paudio->fcc); h->audio_sample = ng_afmt_to_channels[h->audio.fmtid] * ng_afmt_to_bits[h->audio.fmtid] / 8; if (h->lib_audio) { if (!quicktime_supported_audio(h->fh, 0)) { fprintf(stderr,"libquicktime: audio codec not supported\n"); goto fail; } } } if (h->video.fmtid != VIDEO_NONE) { quicktime_set_video(h->fh,1,h->video.width,h->video.height, (float)fps/1000,(char*)pvideo->fcc); if (h->lib_video) { quicktime_set_cmodel(h->fh,pvideo->cmodel); if (!quicktime_supported_video(h->fh, 0)) { fprintf(stderr,"libquicktime: video codec not supported\n"); goto fail; } } } quicktime_set_info(h->fh, "Dumme Bemerkungen gibt's hier umsonst."); return h; fail: if (h->rows) free(h->rows); if (h->data) free(h->data); free(h); return NULL;}static intqt_video(void *handle, struct ng_video_buf *buf){ struct qt_handle *h = handle; unsigned int *src,*dest; int rc,i,n; if (h->lib_video) { unsigned int row,len; char *line; /* QuickTime library expects an array of pointers to image rows (RGB) */ len = h->video.width * 3; for (row = 0, line = buf->data; row < h->video.height; row++, line += len) h->rows[row] = line; rc = quicktime_encode_video(h->fh, h->rows, 0); } else if (h->yuvsign) { dest = (unsigned int *)h->data; src = (unsigned int *)buf->data; n = buf->size / 4; /* U V values are signed but Y R G B values are unsigned. */ for (i = 0; i < n; i++) {#if BYTE_ORDER == BIG_ENDIAN *(dest++) = *(src++) ^ 0x00800080;#else *(dest++) = *(src++) ^ 0x80008000;#endif } rc = quicktime_write_frame(h->fh, h->data, buf->size, 0); } else { rc = quicktime_write_frame(h->fh, buf->data, buf->size, 0); } return rc;}static intqt_audio(void *handle, struct ng_audio_buf *buf){ struct qt_handle *h = handle; int16_t *ch[2]; if (h->lib_audio) { /* FIXME: works for one channel (mono) only */ ch[0] = (int16_t*)buf->data; return quicktime_encode_audio(h->fh, ch, NULL, buf->size / h->audio_sample); } else { return quicktime_write_audio(h->fh, buf->data, buf->size / h->audio_sample, 0); }}static intqt_close(void *handle){ struct qt_handle *h = handle; quicktime_close(h->fh); if (h->rows) free(h->rows); if (h->data) free(h->data); free(h); return 0;}/* ----------------------------------------------------------------------- */static int cmodels[] = { [BC_BGR888] = VIDEO_BGR24, [BC_RGB888] = VIDEO_RGB24, [BC_YUV422] = VIDEO_YUYV, [BC_YUV422P] = VIDEO_YUV422P, [BC_YUV420P] = VIDEO_YUV420P,};static struct qt_video_priv qt_raw = { fcc: QUICKTIME_RAW, libencode: 0,};static struct qt_video_priv qt_yuv2 = { fcc: QUICKTIME_YUV2, yuvsign: 1, libencode: 0,};static struct qt_video_priv qt_yv12 = { fcc: QUICKTIME_YUV420, libencode: 0,};static struct qt_video_priv qt_jpeg = { fcc: QUICKTIME_JPEG, libencode: 0,};static const struct ng_format_list qt_vformats[] = { { name: "raw", ext: "mov", fmtid: VIDEO_RGB24, priv: &qt_raw, },{ name: "yuv2", ext: "mov", fmtid: VIDEO_YUYV, priv: &qt_yuv2, },{ name: "yv12", ext: "mov", fmtid: VIDEO_YUV420P, priv: &qt_yv12, },{ name: "jpeg", ext: "mov", fmtid: VIDEO_JPEG, priv: &qt_jpeg, },{ /* EOF */ }};static struct qt_audio_priv qt_mono8 = { fcc: QUICKTIME_RAW, libencode: 0,};static struct qt_audio_priv qt_mono16 = { fcc: QUICKTIME_TWOS, libencode: 0,};static struct qt_audio_priv qt_stereo = { fcc: QUICKTIME_TWOS, libencode: 0,};static const struct ng_format_list qt_aformats[] = { { name: "mono8", ext: "mov", fmtid: AUDIO_U8_MONO, priv: &qt_mono8, },{ name: "mono16", ext: "mov", fmtid: AUDIO_S16_BE_MONO, priv: &qt_mono16, },{ name: "stereo", ext: "mov", fmtid: AUDIO_S16_BE_STEREO, priv: &qt_stereo, },{ /* EOF */ }};struct ng_writer qt_writer = { name: "qt", desc: "Apple QuickTime format", combined: 1, video: qt_vformats, audio: qt_aformats, wr_open: qt_open, wr_video: qt_video, wr_audio: qt_audio, wr_close: qt_close,};/* ----------------------------------------------------------------------- */#if 0/* debug only */static void dump_codecs(void){ lqt_codec_info_t **info; int i,j; info = lqt_query_registry(1, 1, 1, 1); for (i = 0; info[i] != NULL; i++) { fprintf(stderr,"lqt: %s codec: %s [%s]\n", info[i]->type == LQT_CODEC_AUDIO ? "audio" : "video", info[i]->name,info[i]->long_name); fprintf(stderr," encode: %s\n", info[i]->direction == LQT_DIRECTION_DECODE ? "no" : "yes"); fprintf(stderr," decode: %s\n", info[i]->direction == LQT_DIRECTION_ENCODE ? "no" : "yes"); for (j = 0; j < info[i]->num_fourccs; j++) fprintf(stderr," fcc : %s\n",info[i]->fourccs[j]); for (j = 0; j < info[i]->num_encoding_colormodels; j++) fprintf(stderr," cmodel: %s\n", lqt_get_colormodel_string(info[i]->encoding_colormodels[j])); fprintf(stderr,"\n"); } lqt_destroy_codec_info(info);}#endifstatic struct ng_format_list*qt_list_add(struct ng_format_list* list, char *name, char *desc, char *ext, int fmtid, void *priv){ int n; for (n = 0; list[n].name != NULL; n++) /* nothing */; list = realloc(list,sizeof(struct ng_format_list)*(n+2)); memset(list+n,0,sizeof(struct ng_format_list)*2); list[n].name = strdup(name); list[n].desc = strdup(desc); list[n].ext = strdup(ext); list[n].fmtid = fmtid; list[n].priv = priv; return list;}static struct ng_format_list* video_list(void){ static int debug = 0; lqt_codec_info_t **info; struct ng_format_list *video; int i,j,k,skip,fmtid; unsigned int cmodel; struct qt_video_priv *vp; /* handle video encoders */ video = malloc(sizeof(qt_vformats)); memcpy(video,qt_vformats,sizeof(qt_vformats)); info = lqt_query_registry(0, 1, 1, 0); for (i = 0; info[i] != NULL; i++) { if (debug) { fprintf(stderr,"\nlqt: %s codec: %s [%s]\n", info[i]->type == LQT_CODEC_AUDIO ? "audio" : "video", info[i]->name,info[i]->long_name); for (j = 0; j < info[i]->num_fourccs; j++) fprintf(stderr," fcc : %s\n",info[i]->fourccs[j]); for (j = 0; j < info[i]->num_encoding_colormodels; j++) fprintf(stderr," cmodel: %d [%s]\n", info[i]->encoding_colormodels[j], lqt_get_colormodel_string(info[i]->encoding_colormodels[j])); } /* sanity checks */ if (0 == info[i]->num_fourccs) { if (debug) fprintf(stderr," skipping, no fourcc\n"); continue; } /* avoid dup entries */ skip = 0; for (j = 0; video[j].name != NULL; j++) { const struct qt_video_priv *p = video[j].priv; for (k = 0; k < info[i]->num_fourccs; k++) if (0 == strcmp(p->fcc,info[i]->fourccs[k])) skip = 1; } if (skip) { if (debug) fprintf(stderr," skipping, fourcc already in list\n"); continue; } /* pick colormodel */ fmtid = VIDEO_NONE; cmodel = 0; for (j = 0; j < info[i]->num_encoding_colormodels; j++) { cmodel = info[i]->encoding_colormodels[j]; if (cmodel>= sizeof(cmodels)/sizeof(int)) continue; if (!cmodels[cmodel]) continue; fmtid = cmodels[cmodel]; break; } if (VIDEO_NONE == fmtid) { if (debug) fprintf(stderr," skipping, can't handle color model\n"); continue; } /* all fine */ if (debug) fprintf(stderr," ok, using fmtid %d [%s]\n", fmtid,ng_vfmt_to_desc[fmtid]); vp = malloc(sizeof(*vp)); memset(vp,0,sizeof(*vp)); strcpy(vp->fcc,info[i]->fourccs[0]); vp->libencode = 1; vp->cmodel = cmodel; video = qt_list_add(video,vp->fcc,info[i]->long_name,"mov",fmtid,vp); } lqt_destroy_codec_info(info); return video;}static struct ng_format_list* audio_list(void){ static int debug = 0; lqt_codec_info_t **info; struct ng_format_list *audio; int i,j; struct qt_audio_priv *ap; /* handle video encoders */ audio = malloc(sizeof(qt_aformats)); memcpy(audio,qt_aformats,sizeof(qt_aformats)); info = lqt_query_registry(1, 0, 1, 0); for (i = 0; info[i] != NULL; i++) { if (debug) { fprintf(stderr,"\nlqt: %s codec: %s [%s]\n", info[i]->type == LQT_CODEC_AUDIO ? "audio" : "video", info[i]->name,info[i]->long_name); for (j = 0; j < info[i]->num_fourccs; j++) fprintf(stderr," fcc : %s\n",info[i]->fourccs[j]); } /* sanity checks */ if (0 == info[i]->num_fourccs) { if (debug) fprintf(stderr," skipping, no fourcc\n"); continue; } /* skip uncompressed formats */ if (0 == strcmp(info[i]->fourccs[0],QUICKTIME_RAW) || 0 == strcmp(info[i]->fourccs[0],QUICKTIME_ULAW) || 0 == strcmp(info[i]->fourccs[0],QUICKTIME_IMA4) || /* ??? */ 0 == strcmp(info[i]->fourccs[0],QUICKTIME_TWOS)) { if (debug) fprintf(stderr," skipping, uncompressed\n"); continue; } /* all fine */ if (debug) fprintf(stderr," ok\n"); ap = malloc(sizeof(*ap)); memset(ap,0,sizeof(*ap)); strcpy(ap->fcc,info[i]->fourccs[0]); ap->libencode = 1; audio = qt_list_add(audio,ap->fcc,info[i]->long_name,"mov", AUDIO_S16_NATIVE_MONO,ap); } lqt_destroy_codec_info(info); return audio;}extern void ng_plugin_init(void);void ng_plugin_init(void){ qt_writer.video = video_list(); qt_writer.audio = audio_list(); ng_writer_register(NG_PLUGIN_MAGIC,__FILE__,&qt_writer);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -