diff options
author | Fabrice Bellard <fabrice@bellard.org> | 2001-09-24 23:22:25 +0000 |
---|---|---|
committer | Fabrice Bellard <fabrice@bellard.org> | 2001-09-24 23:22:25 +0000 |
commit | a38469e1da7b4829a2fba4279d8420a33f96832e (patch) | |
tree | 985988f31f088b05e7ae5e7582a6147ef33209d9 | |
parent | 2744a37fac86eee2b2af652493d6cf8aa5f4c375 (diff) | |
download | ffmpeg-a38469e1da7b4829a2fba4279d8420a33f96832e.tar.gz |
unified grab & convertion loops (should be easier to achieve correct synchronization now - but still work to do!) - added ffplay support
Originally committed as revision 144 to svn://svn.ffmpeg.org/ffmpeg/trunk
-rw-r--r-- | ffmpeg.c | 605 |
1 files changed, 170 insertions, 435 deletions
@@ -97,6 +97,7 @@ static char *str_copyright = NULL; static char *str_comment = NULL; static int do_benchmark = 0; static int do_hex_dump = 0; +static int do_play = 0; typedef struct AVOutputStream { int file_index; /* file index */ @@ -188,425 +189,30 @@ static int read_key(void) return -1; } -#define AUDIO_FIFO_SIZE 8192 +#else -/* main loop for grabbing */ -int av_grab(AVFormatContext *s) +/* no interactive support */ +static void term_exit(void) { - UINT8 audio_buf[AUDIO_FIFO_SIZE]; - UINT8 audio_buf1[AUDIO_FIFO_SIZE]; - UINT8 audio_out[AUDIO_FIFO_SIZE]; - UINT8 video_buffer[1024*1024]; - char buf[256]; - short *samples; - URLContext *audio_handle = NULL, *video_handle = NULL; - int ret; - AVCodecContext *enc, *first_video_enc = NULL; - int frame_size, frame_bytes; - int use_audio, use_video; - int frame_rate, sample_rate, channels; - int width, height, frame_number, i, pix_fmt = 0; - AVOutputStream *ost_table[s->nb_streams], *ost; - UINT8 *picture_in_buf = NULL, *picture_420p = NULL; - int audio_fifo_size = 0, picture_size = 0; - INT64 time_start; - - /* init output stream info */ - for(i=0;i<s->nb_streams;i++) - ost_table[i] = NULL; - - /* output stream init */ - for(i=0;i<s->nb_streams;i++) { - ost = av_mallocz(sizeof(AVOutputStream)); - if (!ost) - goto fail; - ost->index = i; - ost->st = s->streams[i]; - ost_table[i] = ost; - } - - use_audio = 0; - use_video = 0; - frame_rate = 0; - sample_rate = 0; - frame_size = 0; - channels = 1; - width = 0; - height = 0; - frame_number = 0; - - for(i=0;i<s->nb_streams;i++) { - AVCodec *codec; - - ost = ost_table[i]; - enc = &ost->st->codec; - codec = avcodec_find_encoder(enc->codec_id); - if (!codec) { - fprintf(stderr, "Unknown codec\n"); - return -1; - } - if (avcodec_open(enc, codec) < 0) { - fprintf(stderr, "Incorrect encode parameters\n"); - return -1; - } - switch(enc->codec_type) { - case CODEC_TYPE_AUDIO: - use_audio = 1; - if (enc->sample_rate > sample_rate) - sample_rate = enc->sample_rate; - if (enc->frame_size > frame_size) - frame_size = enc->frame_size; - if (enc->channels > channels) - channels = enc->channels; - break; - case CODEC_TYPE_VIDEO: - if (!first_video_enc) - first_video_enc = enc; - use_video = 1; - if (enc->frame_rate > frame_rate) - frame_rate = enc->frame_rate; - if (enc->width > width) - width = enc->width; - if (enc->height > height) - height = enc->height; - break; - } - } - - /* audio */ - samples = NULL; - if (use_audio) { - snprintf(buf, sizeof(buf), "audio:%d,%d", sample_rate, channels); - ret = url_open(&audio_handle, buf, URL_RDONLY); - if (ret < 0) { - fprintf(stderr, "Could not open audio device: disabling audio capture\n"); - use_audio = 0; - } else { - URLFormat f; - /* read back exact grab parameters */ - if (url_getformat(audio_handle, &f) < 0) { - fprintf(stderr, "could not read back video grab parameters\n"); - goto fail; - } - sample_rate = f.sample_rate; - channels = f.channels; - audio_fifo_size = ((AUDIO_FIFO_SIZE / 2) / audio_handle->packet_size) * - audio_handle->packet_size; - fprintf(stderr, "Audio sampling: %d Hz, %s\n", - sample_rate, channels == 2 ? "stereo" : "mono"); - } - } - - /* video */ - if (use_video) { - snprintf(buf, sizeof(buf), "video:%d,%d,%f", - width, height, (float)frame_rate / FRAME_RATE_BASE); - - ret = url_open(&video_handle, buf, URL_RDONLY); - if (ret < 0) { - fprintf(stderr,"Could not init video 4 linux capture: disabling video capture\n"); - use_video = 0; - } else { - URLFormat f; - const char *pix_fmt_str; - /* read back exact grab parameters */ - if (url_getformat(video_handle, &f) < 0) { - fprintf(stderr, "could not read back video grab parameters\n"); - goto fail; - } - width = f.width; - height = f.height; - pix_fmt = f.pix_fmt; - switch(pix_fmt) { - case PIX_FMT_YUV420P: - pix_fmt_str = "420P"; - break; - case PIX_FMT_YUV422: - pix_fmt_str = "422"; - break; - case PIX_FMT_RGB24: - pix_fmt_str = "RGB24"; - break; - case PIX_FMT_BGR24: - pix_fmt_str = "BGR24"; - break; - default: - pix_fmt_str = "???"; - break; - } - picture_size = video_handle->packet_size; - picture_in_buf = malloc(picture_size); - if (!picture_in_buf) - goto fail; - /* allocate a temporary picture if not grabbing in 420P format */ - if (pix_fmt != PIX_FMT_YUV420P) { - picture_420p = malloc((width * height * 3) / 2); - } - fprintf(stderr, "Video sampling: %dx%d, %s format, %0.2f fps\n", - width, height, pix_fmt_str, (float)frame_rate / FRAME_RATE_BASE); - } - } - - if (!use_video && !use_audio) { - fprintf(stderr,"Could not open grab devices : exiting\n"); - exit(1); - } - - /* init built in conversion functions */ - for(i=0;i<s->nb_streams;i++) { - ost = ost_table[i]; - enc = &ost->st->codec; - switch(enc->codec_type) { - case CODEC_TYPE_AUDIO: - ost->audio_resample = 0; - if ((enc->channels != channels || - enc->sample_rate != sample_rate)) { - ost->audio_resample = 1; - ost->resample = audio_resample_init(enc->channels, channels, - enc->sample_rate, sample_rate); - } - if (fifo_init(&ost->fifo, (2 * audio_fifo_size * enc->sample_rate * - enc->channels) / sample_rate)) - goto fail; - break; - case CODEC_TYPE_VIDEO: - ost->video_resample = 0; - if (enc->width != width || - enc->height != height) { - UINT8 *buf; - ost->video_resample = 1; - buf = malloc((enc->width * enc->height * 3) / 2); - if (!buf) - goto fail; - ost->pict_tmp.data[0] = buf; - ost->pict_tmp.data[1] = buf + enc->width * height; - ost->pict_tmp.data[2] = ost->pict_tmp.data[1] + (enc->width * height) / 4; - ost->pict_tmp.linesize[0] = enc->width; - ost->pict_tmp.linesize[1] = enc->width / 2; - ost->pict_tmp.linesize[2] = enc->width / 2; - ost->img_resample_ctx = img_resample_init( - ost->st->codec.width, ost->st->codec.height, - width, height); - } - } - } - - fprintf(stderr, "Press [q] to stop encoding\n"); - - s->format->write_header(s); - time_start = gettime(); - term_init(); - - for(;;) { - /* if 'q' pressed, exits */ - if (read_key() == 'q') - break; - - /* read & compress audio frames */ - if (use_audio) { - int ret, nb_samples, nb_samples_out; - UINT8 *buftmp; - - for(;;) { - ret = url_read(audio_handle, audio_buf, audio_fifo_size); - if (ret <= 0) - break; - /* fill each codec fifo by doing the right sample - rate conversion. This is not optimal because we - do too much work, but it is easy to do */ - nb_samples = ret / (channels * 2); - for(i=0;i<s->nb_streams;i++) { - ost = ost_table[i]; - enc = &ost->st->codec; - if (enc->codec_type == CODEC_TYPE_AUDIO) { - /* rate & stereo convertion */ - if (!ost->audio_resample) { - buftmp = audio_buf; - nb_samples_out = nb_samples; - } else { - buftmp = audio_buf1; - nb_samples_out = audio_resample(ost->resample, - (short *)buftmp, (short *)audio_buf, - nb_samples); - } - fifo_write(&ost->fifo, buftmp, nb_samples_out * enc->channels * 2, - &ost->fifo.wptr); - } - } - - /* compress as many frame as possible with each audio codec */ - for(i=0;i<s->nb_streams;i++) { - ost = ost_table[i]; - enc = &ost->st->codec; - if (enc->codec_type == CODEC_TYPE_AUDIO) { - frame_bytes = enc->frame_size * 2 * enc->channels; - - while (fifo_read(&ost->fifo, audio_buf, - frame_bytes, &ost->fifo.rptr) == 0) { - ret = avcodec_encode_audio(enc, - audio_out, sizeof(audio_out), - (short *)audio_buf); - s->format->write_packet(s, ost->index, audio_out, ret); - } - } - } - } - } - - if (use_video) { - AVPicture *picture1, *picture2, *picture; - AVPicture picture_tmp0, picture_tmp1; - - ret = url_read(video_handle, picture_in_buf, picture_size); - if (ret < 0) - break; - - picture2 = &picture_tmp0; - avpicture_fill(picture2, picture_in_buf, pix_fmt, width, height); - - if (pix_fmt != PIX_FMT_YUV420P) { - picture = &picture_tmp1; - avpicture_fill(picture, picture_420p, - PIX_FMT_YUV420P, width, height); - img_convert(picture, PIX_FMT_YUV420P, - picture2, pix_fmt, - width, height); - } else { - picture = picture2; - } - - for(i=0;i<s->nb_streams;i++) { - ost = ost_table[i]; - enc = &ost->st->codec; - if (enc->codec_type == CODEC_TYPE_VIDEO) { - int n1, n2, nb; - - /* feed each codec with its requested frame rate */ - n1 = ((INT64)frame_number * enc->frame_rate) / frame_rate; - n2 = (((INT64)frame_number + 1) * enc->frame_rate) / frame_rate; - nb = n2 - n1; - if (nb > 0) { - /* resize the picture if needed */ - if (ost->video_resample) { - picture1 = &ost->pict_tmp; - img_resample(ost->img_resample_ctx, - picture1, picture); - } else { - picture1 = picture; - } - ret = avcodec_encode_video(enc, video_buffer, - sizeof(video_buffer), - picture1); - s->format->write_packet(s, ost->index, video_buffer, ret); - } - } - } - frame_number++; - } - - /* write report */ - { - char buf[1024]; - INT64 total_size; - float ti, bitrate; - static float last_ti; - INT64 ti1; - - total_size = url_ftell(&s->pb); - ti1 = gettime() - time_start; - /* check elapsed time */ - if (recording_time && ti1 >= recording_time) - break; - - ti = ti1 / 1000000.0; - if (ti < 0.1) - ti = 0.1; - /* dispaly twice per second */ - if ((ti - last_ti) >= 0.5) { - last_ti = ti; - bitrate = (int)((total_size * 8) / ti / 1000.0); - - buf[0] = '\0'; - if (use_video) { - sprintf(buf + strlen(buf), "frame=%5d fps=%4.1f q=%2d ", - frame_number, (float)frame_number / ti, first_video_enc->quality); - } - - sprintf(buf + strlen(buf), "size=%8LdkB time=%0.1f bitrate=%6.1fkbits/s", - total_size / 1024, ti, bitrate); - fprintf(stderr, "%s \r", buf); - fflush(stderr); - } - } - } - term_exit(); - - for(i=0;i<s->nb_streams;i++) { - ost = ost_table[i]; - enc = &ost->st->codec; - avcodec_close(enc); - } - s->format->write_trailer(s); - - if (audio_handle) - url_close(audio_handle); - - if (video_handle) - url_close(video_handle); - - /* write report */ - { - float ti, bitrate; - INT64 total_size; - - total_size = url_ftell(&s->pb); - - ti = (gettime() - time_start) / 1000000.0; - if (ti < 0.1) - ti = 0.1; - bitrate = (int)((total_size * 8) / ti / 1000.0); +} - fprintf(stderr, "\033[K\nTotal time = %0.1f s, %Ld KBytes, %0.1f kbits/s\n", - ti, total_size / 1024, bitrate); - if (use_video) { - fprintf(stderr, "Total frames = %d\n", frame_number); - } - } +static void term_init(void) +{ +} - ret = 0; - fail1: - if (picture_in_buf) - free(picture_in_buf); - if (picture_420p) - free(picture_420p); - for(i=0;i<s->nb_streams;i++) { - ost = ost_table[i]; - if (ost) { - if (ost->fifo.buffer) - fifo_free(&ost->fifo); - if (ost->pict_tmp.data[0]) - free(ost->pict_tmp.data[0]); - if (ost->video_resample) - img_resample_close(ost->img_resample_ctx); - if (ost->audio_resample) - audio_resample_close(ost->resample); - free(ost); - } - } - return ret; - fail: - ret = -ENOMEM; - goto fail1; +static int read_key(void) +{ + return -1; } -#endif /* CONFIG_WIN32 */ +#endif int read_ffserver_streams(AVFormatContext *s, const char *filename) { int i; AVFormatContext *ic; - ic = av_open_input_file(filename, FFM_PACKET_SIZE); + ic = av_open_input_file(filename, NULL, FFM_PACKET_SIZE, NULL); if (!ic) return -EIO; /* copy stream format */ @@ -1156,9 +762,22 @@ static int av_encode(AVFormatContext **output_files, /* open files and write file headers */ for(i=0;i<nb_output_files;i++) { os = output_files[i]; - os->format->write_header(os); + if (os->format->write_header(os) < 0) { + fprintf(stderr, "Could not write header for output file #%d (incorrect codec paramters ?)\n", i); + ret = -EINVAL; + goto fail; + } } +#ifndef CONFIG_WIN32 + if (!do_play) { + fprintf(stderr, "Press [q] to stop encoding\n"); + } else { + fprintf(stderr, "Press [q] to stop playing\n"); + } +#endif + term_init(); + start_time = gettime(); min_pts = 0; for(;;) { @@ -1171,8 +790,12 @@ static int av_encode(AVFormatContext **output_files, AVPicture picture; short samples[AVCODEC_MAX_AUDIO_FRAME_SIZE / 2]; - /* select the input file with the smallest pts */ redo: + /* if 'q' pressed, exits */ + if (read_key() == 'q') + break; + + /* select the input file with the smallest pts */ file_index = -1; min_pts = MAXINT64; for(i=0;i<nb_istreams;i++) { @@ -1189,7 +812,6 @@ static int av_encode(AVFormatContext **output_files, if (recording_time > 0 && min_pts >= recording_time) break; /* read a packet from it and output it in the fifo */ - is = input_files[file_index]; if (av_read_packet(is, &pkt) < 0) { file_table[file_index].eof_reached = 1; @@ -1358,6 +980,7 @@ static int av_encode(AVFormatContext **output_files, } } } + term_exit(); /* dump report by using the first video and audio streams */ { @@ -2090,6 +1713,95 @@ void opt_output_file(const char *filename) video_codec_id = CODEC_ID_NONE; } +#ifdef CONFIG_GRAB + +/* prepare dummy protocols for grab */ +void prepare_grab(void) +{ + int has_video, has_audio, i, j; + AVFormatContext *oc; + AVFormatContext *ic; + AVFormatParameters ap1, *ap = &ap1; + + /* see if audio/video inputs are needed */ + has_video = 0; + has_audio = 0; + memset(ap, 0, sizeof(*ap)); + for(j=0;j<nb_output_files;j++) { + oc = output_files[j]; + for(i=0;i<oc->nb_streams;i++) { + AVCodecContext *enc = &oc->streams[i]->codec; + switch(enc->codec_type) { + case CODEC_TYPE_AUDIO: + if (enc->sample_rate > ap->sample_rate) + ap->sample_rate = enc->sample_rate; + if (enc->channels > ap->channels) + ap->channels = enc->channels; + has_audio = 1; + break; + case CODEC_TYPE_VIDEO: + if (enc->width > ap->width) + ap->width = enc->width; + if (enc->height > ap->height) + ap->height = enc->height; + if (enc->frame_rate > ap->frame_rate) + ap->frame_rate = enc->frame_rate; + has_video = 1; + break; + } + } + } + + if (has_video == 0 && has_audio == 0) { + fprintf(stderr, "Output file must have at least one audio or video stream\n"); + exit(1); + } + + if (has_video) { + ic = av_open_input_file("", "video_grab_device", 0, ap); + if (!ic) { + fprintf(stderr, "Could not open video grab device\n"); + exit(1); + } + input_files[nb_input_files] = ic; + dump_format(ic, nb_input_files, v4l_device, 0); + nb_input_files++; + } + if (has_audio) { + ic = av_open_input_file("", "audio_device", 0, ap); + if (!ic) { + fprintf(stderr, "Could not open audio grab device\n"); + exit(1); + } + input_files[nb_input_files] = ic; + dump_format(ic, nb_input_files, audio_device, 0); + nb_input_files++; + } +} + +#else + +void prepare_grab(void) +{ + fprintf(stderr, "Must supply at least one input file\n"); + exit(1); +} + +#endif + +/* open the necessary output devices for playing */ +void prepare_play(void) +{ + file_format = guess_format("audio_device", NULL, NULL); + if (!file_format) { + fprintf(stderr, "Could not find audio device\n"); + exit(1); + } + + opt_output_file(audio_device); +} + + #ifndef CONFIG_WIN32 INT64 getutime(void) { @@ -2165,13 +1877,24 @@ void show_formats(void) void show_help(void) { + const char *prog; const OptionDef *po; int i, expert; + + prog = do_play ? "ffplay" : "ffmpeg"; - printf("ffmpeg version " FFMPEG_VERSION ", Copyright (c) 2000,2001 Gerard Lantau\n" - "usage: ffmpeg [[options] -i input_file]... {[options] outfile}...\n" - "Hyper fast MPEG1/MPEG4/H263/RV and AC3/MPEG audio encoder\n" - "\n" + printf("%s version " FFMPEG_VERSION ", Copyright (c) 2000, 2001 Gerard Lantau\n", + prog); + + if (!do_play) { + printf("usage: ffmpeg [[options] -i input_file]... {[options] outfile}...\n" + "Hyper fast MPEG1/MPEG4/H263/RV and AC3/MPEG audio encoder\n"); + } else { + printf("usage: ffplay [options] input_file...\n" + "Simple audio player\n"); + } + + printf("\n" "Main options are:\n"); for(i=0;i<2;i++) { if (i == 1) @@ -2246,12 +1969,19 @@ int main(int argc, char **argv) int optindex, i; const char *opt, *arg; const OptionDef *po; + INT64 ti; register_all(); + /* detect if invoked as player */ + i = strlen(argv[0]); + if (i >= 6 && !strcmp(argv[0] + i - 6, "ffplay")) + do_play = 1; + if (argc <= 1) show_help(); - + + /* parse options */ optindex = 1; while (optindex < argc) { opt = argv[optindex++]; @@ -2280,35 +2010,40 @@ int main(int argc, char **argv) po->u.func_arg(arg); } } else { - opt_output_file(opt); + if (!do_play) { + opt_output_file(opt); + } else { + opt_input_file(opt); + } } } - if (nb_input_files == 0) { -#ifdef CONFIG_GRAB - if (nb_output_files != 1) { - fprintf(stderr, "Only one output file supported when grabbing\n"); - exit(1); - } - av_grab(output_files[0]); -#else - fprintf(stderr, "Must supply at least one input file\n"); -#endif - } else { - INT64 ti; - + if (!do_play) { + /* file converter / grab */ if (nb_output_files <= 0) { fprintf(stderr, "Must supply at least one output file\n"); exit(1); } - ti = getutime(); - av_encode(output_files, nb_output_files, input_files, nb_input_files, - stream_maps, nb_stream_maps); - ti = getutime() - ti; - if (do_benchmark) { - printf("bench: utime=%0.3fs\n", ti / 1000000.0); + + if (nb_input_files == 0) { + prepare_grab(); } + } else { + /* player */ + if (nb_input_files <= 0) { + fprintf(stderr, "Must supply at least one input file\n"); + exit(1); + } + prepare_play(); + } + + ti = getutime(); + av_encode(output_files, nb_output_files, input_files, nb_input_files, + stream_maps, nb_stream_maps); + ti = getutime() - ti; + if (do_benchmark) { + printf("bench: utime=%0.3fs\n", ti / 1000000.0); } /* close files */ |