Hi,<br><br>I have modified muxer program that saves h264 video to disk of 01 minute duration, as follows:<br><br>******************************<div id=":11t">************************************************************<br>
/*<br> * Copyright (c) 2001 Fabrice Bellard<br>
*<br> * Permission is hereby granted, free of charge, to any person obtaining a copy<br> * of this software and associated documentation files (the "Software"), to deal<br> * in the Software without restriction, including without limitation the rights<br>
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell<br> * copies of the Software, and to permit persons to whom the Software is<br> * furnished to do so, subject to the following conditions:<br> *<br>
* The above copyright notice and this permission notice shall be included in<br> * all copies or substantial portions of the Software.<br> *<br> * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR<br>
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,<br> * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL<br> * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER<br>
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,<br> * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN<br> * THE SOFTWARE.<br> */<br><br>/**<br> * @file<br> * libavcodec API use example.<br>
*<br> * Note that libavcodec only handles codecs (mpeg, mpeg4, etc...),<br> * not file formats (avi, vob, mp4, mov, mkv, mxf, flv, mpegts, mpegps, etc...). See library 'libavformat' for the<br> * format handling<br>
*/<br><br>#include <Windows.h><br>#include <math.h><br>extern "C"<br>{<br>#include "libavcodec/avcodec.h"<br>#include "libavformat/avformat.h"<br>#include "libavdevice/avdevice.h"<br>
#include "libswscale/swscale.h"<br>#include "libavutil/dict.h"<br>#include "libavutil/error.h"<br>#include "libavutil/opt.h"<br>}<br><br>#define DECODER_WIDTH 640<br>#define DECODER_HEIGHT 480<br>
<br>#define ENCODER_WIDTH 640<br>#define ENCODER_HEIGHT 480<br><br>/* 5 seconds stream duration */<br>#define STREAM_DURATION 60.0<br>#define STREAM_FRAME_RATE 25 /* 25 images/s */<br>#define STREAM_NB_FRAMES ((int)(STREAM_DURATION * STREAM_FRAME_RATE))<br>
#define STREAM_PIX_FMT AV_PIX_FMT_YUV420P /* default pix_fmt */<br><br>static int sws_flags = SWS_BICUBIC;<br><br>/**************************************************************/<br>/* audio output */<br><br>static float t, tincr, tincr2;<br>
static int16_t *samples;<br>static int audio_input_frame_size;<br><br>/* Add an output stream. */<br>static AVStream *add_stream(AVFormatContext *oc, AVCodec **codec,<br> enum AVCodecID codec_id)<br>
{<br> AVCodecContext *c;<br> AVStream *st;<br><br> /* find the encoder */<br> *codec = avcodec_find_encoder(codec_id);<br> if (!(*codec)) {<br> fprintf(stderr, "Could not find codec\n");<br>
exit(1);<br> }<br><br> st = avformat_new_stream(oc, *codec);<br> if (!st) {<br> fprintf(stderr, "Could not allocate stream\n");<br> exit(1);<br> }<br> st->id = oc->nb_streams-1;<br>
c = st->codec;<br><br> switch ((*codec)->type) {<br> case AVMEDIA_TYPE_AUDIO:<br> st->id = 1;<br> c->sample_fmt = AV_SAMPLE_FMT_S16;<br> c->bit_rate = 64000;<br> c->sample_rate = 44100;<br>
c->channels = 2;<br> break;<br><br> case AVMEDIA_TYPE_VIDEO:<br> avcodec_get_context_defaults3(c, *codec);<br> c->codec_id = codec_id;<br><br> c->bit_rate = 400000;<br> /* Resolution must be a multiple of two. */<br>
c->width = ENCODER_WIDTH;<br> c->height = ENCODER_HEIGHT;<br> /* timebase: This is the fundamental unit of time (in seconds) in terms<br> * of which frame timestamps are represented. For fixed-fps content,<br>
* timebase should be 1/framerate and timestamp increments should be<br> * identical to 1. */<br> c->time_base.den = STREAM_FRAME_RATE;<br> c->time_base.num = 1;<br> c->gop_size = 12; /* emit one intra frame every twelve frames at most */<br>
c->pix_fmt = STREAM_PIX_FMT;<br> if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) {<br> /* just for testing, we also add B frames */<br> c->max_b_frames = 2;<br> }<br>
if (c->codec_id == AV_CODEC_ID_MPEG1VIDEO) {<br>
/* Needed to avoid using macroblocks in which some coeffs overflow.<br> * This does not happen with normal video, it just happens here as<br> * the motion of the chroma plane does not match the luma plane. */<br>
c->mb_decision = 2;<br> }<br> break;<br><br> default:<br> break;<br> }<br><br> /* Some formats want stream headers to be separate. */<br> if (oc->oformat->flags & AVFMT_GLOBALHEADER)<br>
c->flags |= CODEC_FLAG_GLOBAL_HEADER;<br><br> return st;<br>}<br><br>/**************************************************************/<br>/* audio output */<br><br><br>static void open_audio(AVFormatContext *oc, AVCodec *codec, AVStream *st)<br>
{<br> AVCodecContext *c;<br><br> c = st->codec;<br><br> /* open it */<br> if (avcodec_open2(c, codec, NULL) < 0) {<br> fprintf(stderr, "Could not open audio codec\n");<br> exit(1);<br>
}<br><br> /* init signal generator */<br> t = 0;<br> tincr = 2 * M_PI * 110.0 / c->sample_rate;<br> /* increment frequency by 110 Hz per second */<br> tincr2 = 2 * M_PI * 110.0 / c->sample_rate / c->sample_rate;<br>
<br> if (c->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)<br> audio_input_frame_size = 10000;<br> else<br> audio_input_frame_size = c->frame_size;<br> samples = (int16_t *) av_malloc(audio_input_frame_size *<br>
av_get_bytes_per_sample(c->sample_fmt) *<br> c->channels);<br> if (!samples) {<br> fprintf(stderr, "Could not allocate audio samples buffer\n");<br>
exit(1);<br> }<br>}<br><br>/* Prepare a 16 bit dummy audio frame of 'frame_size' samples and<br> * 'nb_channels' channels. */<br>static void get_audio_frame(int16_t *samples, int frame_size, int nb_channels)<br>
{<br> int j, i, v;<br> int16_t *q;<br><br> q = samples;<br> for (j = 0; j < frame_size; j++) {<br> v = (int)(sin(t) * 10000);<br> for (i = 0; i < nb_channels; i++)<br> *q++ = v;<br>
t += tincr;<br> tincr += tincr2;<br> }<br>}<br><br>static void write_audio_frame(AVFormatContext *oc, AVStream *st)<br>{<br> AVCodecContext *c;<br> AVPacket pkt = { 0 }; // data and size must be 0;<br>
AVFrame *frame = avcodec_alloc_frame();<br> int got_packet, ret;<br><br> av_init_packet(&pkt);<br> c = st->codec;<br><br> get_audio_frame(samples, audio_input_frame_size, c->channels);<br> frame->nb_samples = audio_input_frame_size;<br>
avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt,<br> (uint8_t *)samples,<br> audio_input_frame_size *<br> av_get_bytes_per_sample(c->sample_fmt) *<br>
c->channels, 1);<br><br> ret = avcodec_encode_audio2(c, &pkt, frame, &got_packet);<br> if (ret < 0) {<br> fprintf(stderr, "Error encoding audio frame\n");<br>
exit(1);<br> }<br><br> if (!got_packet)<br> return;<br><br> pkt.stream_index = st->index;<br><br> /* Write the compressed frame to the media file. */<br> if (av_interleaved_write_frame(oc, &pkt) != 0) {<br>
fprintf(stderr, "Error while writing audio frame\n");<br> exit(1);<br> }<br> avcodec_free_frame(&frame);<br>}<br><br>static void close_audio(AVFormatContext *oc, AVStream *st)<br>{<br> avcodec_close(st->codec);<br>
<br> av_free(samples);<br>}<br><br>/**************************************************************/<br>/* video output */<br><br>static AVFrame *frame;<br>static AVPicture src_picture, dst_picture;<br>static int frame_count;<br>
<br>static void open_video(AVFormatContext *oc, AVCodec *codec, AVStream *st)<br>{<br> int ret;<br> AVCodecContext *c = st->codec;<br><br> /* open the codec */<br> if (avcodec_open2(c, codec, NULL) < 0) {<br>
fprintf(stderr, "Could not open video codec\n");<br> exit(1);<br> }<br><br> /* allocate and init a re-usable frame */<br> frame = avcodec_alloc_frame();<br> if (!frame) {<br> fprintf(stderr, "Could not allocate video frame\n");<br>
exit(1);<br> }<br><br> /* Allocate the encoded raw picture. */<br> ret = avpicture_alloc(&dst_picture, c->pix_fmt, c->width, c->height);<br> if (ret < 0) {<br> fprintf(stderr, "Could not allocate picture\n");<br>
exit(1);<br> }<br><br> /* If the output format is not YUV420P, then a temporary YUV420P<br> * picture is needed too. It is then converted to the required<br> * output format. */<br> if (1) {<br> ret = avpicture_alloc(&src_picture, PIX_FMT_YUV420P, DECODER_WIDTH, DECODER_HEIGHT);<br>
if (ret < 0) {<br> fprintf(stderr, "Could not allocate temporary picture\n");<br> exit(1);<br> }<br> }<br> //if (c->pix_fmt != AV_PIX_FMT_YUV420P) {<br> // ret = avpicture_alloc(&src_picture, AV_PIX_FMT_YUV420P, c->width, c->height);<br>
// if (ret < 0) {<br> // fprintf(stderr, "Could not allocate temporary picture\n");<br> // exit(1);<br> // }<br> //}<br><br> /* copy data and linesize picture pointers to frame */<br>
*((AVPicture *)frame) = dst_picture;<br>}<br><br>/* Prepare a dummy image. */<br>static void fill_yuv_image(AVPicture *pict, int frame_index,<br> int width, int height)<br>{<br> int x, y, i;<br>
<br> i = frame_index;<br><br> /* Y */<br> for (y = 0; y < height; y++)<br> for (x = 0; x < width; x++)<br> pict->data[0][y * pict->linesize[0] + x] = x + y + i * 3;<br><br> /* Cb and Cr */<br>
for (y = 0; y < height / 2; y++) {<br> for (x = 0; x < width / 2; x++) {<br> pict->data[1][y * pict->linesize[1] + x] = 128 + y + i * 2;<br> pict->data[2][y * pict->linesize[2] + x] = 64 + x + i * 5;<br>
}<br> }<br>}<br><br>static void write_video_frame(AVFormatContext *oc, AVStream *st)<br>{<br> int ret;<br> static struct SwsContext *sws_ctx;<br> AVCodecContext *c = st->codec;<br><br> if (frame_count >= STREAM_NB_FRAMES) {<br>
/* No more frames to compress. The codec has a latency of a few<br> * frames if using B-frames, so we get the last frames by<br> * passing the same picture again. */<br> } else {<br> if (c->pix_fmt != AV_PIX_FMT_YUV420P) {<br>
/* as we only generate a YUV420P picture, we must convert it<br> * to the codec pixel format if needed */<br> if (!sws_ctx) {<br> sws_ctx = sws_getContext(c->width, c->height, AV_PIX_FMT_YUV420P,<br>
c->width, c->height, c->pix_fmt,<br> sws_flags, NULL, NULL, NULL);<br> if (!sws_ctx) {<br> fprintf(stderr,<br>
"Could not initialize the conversion context\n");<br> exit(1);<br> }<br> }<br> fill_yuv_image(&src_picture, frame_count, c->width, c->height);<br>
sws_scale(sws_ctx,<br> (const uint8_t * const *)src_picture.data, src_picture.linesize,<br> 0, c->height, dst_picture.data, dst_picture.linesize);<br> } else <br>
{<br> /* as we only generate a YUV420P picture, we must convert it<br> * to the codec pixel format if needed */<br> if (!sws_ctx) <br> {<br> sws_ctx = sws_getContext( DECODER_WIDTH, DECODER_HEIGHT, PIX_FMT_YUV420P,<br>
c->width, c->height, c->pix_fmt,<br> sws_flags, NULL, NULL, NULL);<br> if (!sws_ctx) <br> {<br> fprintf(stderr,<br> "Could not initialize the conversion context\n");<br>
exit(1);<br> }<br> }<br> fill_yuv_image(&src_picture, frame_count, DECODER_WIDTH, DECODER_HEIGHT);<br> sws_scale(sws_ctx,<br> (const uint8_t * const *)src_picture.data, src_picture.linesize,<br>
0, DECODER_WIDTH, dst_picture.data, dst_picture.linesize);<br> //fill_yuv_image(&dst_picture, frame_count, c->width, c->height);<br> }<br> }<br><br> if (oc->oformat->flags & AVFMT_RAWPICTURE) {<br>
/* Raw video case - directly store the picture in the packet */<br> AVPacket pkt;<br> av_init_packet(&pkt);<br><br> pkt.flags |= AV_PKT_FLAG_KEY;<br> pkt.stream_index = st->index;<br>
pkt.data = dst_picture.data[0];<br> pkt.size = sizeof(AVPicture);<br><br> ret = av_interleaved_write_frame(oc, &pkt);<br> } else {<br> /* encode the image */<br> AVPacket pkt;<br>
int got_output;<br><br> av_init_packet(&pkt);<br> pkt.data = NULL; // packet data will be allocated by the encoder<br> pkt.size = 0;<br><br> ret = avcodec_encode_video2(c, &pkt, frame, &got_output);<br>
if (ret < 0) {<br> fprintf(stderr, "Error encoding video frame\n");<br> exit(1);<br> }<br><br> /* If size is zero, it means the image was buffered. */<br> if (got_output) {<br>
if (c->coded_frame->key_frame)<br> pkt.flags |= AV_PKT_FLAG_KEY;<br><br> pkt.stream_index = st->index;<br><br> /* Write the compressed frame to the media file. */<br>
ret = av_interleaved_write_frame(oc, &pkt);<br> } else {<br> ret = 0;<br> }<br> }<br> if (ret != 0) {<br> fprintf(stderr, "Error while writing video frame\n");<br>
exit(1);<br> }<br> frame_count++;<br>}<br><br>static void close_video(AVFormatContext *oc, AVStream *st)<br>{<br> avcodec_close(st->codec);<br> av_free(src_picture.data[0]);<br> av_free(dst_picture.data[0]);<br>
av_free(frame);<br>}<br><br>/**************************************************************/<br>/* media file output */<br><br>int main(int argc, char **argv)<br>{<br> char filename[99]="";<br> AVOutputFormat *fmt;<br>
AVFormatContext *oc;<br> AVStream *audio_st, *video_st;<br> AVCodec *audio_codec, *video_codec;<br> double audio_pts, video_pts;<br> int i;<br><br> /* Initialize libavcodec, and register all codecs and formats. */<br>
av_register_all();<br><br> if (argc != 2) {<br> printf("usage: %s output_file\n"<br> "API example program to output a media file with libavformat.\n"<br> "This program generates a synthetic audio and video stream, encodes and\n"<br>
"muxes them into a file named output_file.\n"<br> "The output format is automatically guessed according to the file extension.\n"<br> "Raw images can also be output by using '%%d' in the filename.\n"<br>
"\n", argv[0]);<br> return 1;<br> }<br><br> strcpy(filename,"a.h264");<br> /* allocate the output media context */<br> avformat_alloc_output_context2(&oc, NULL, NULL, filename);<br>
if (!oc) {<br> printf("Could not deduce output format from file extension: using MPEG.\n");<br> avformat_alloc_output_context2(&oc, NULL, "mpeg", filename);<br> }<br> if (!oc) {<br>
return 1;<br> }<br> fmt = oc->oformat;<br><br> /* Add the audio and video streams using the default format codecs<br> * and initialize the codecs. */<br> video_st = NULL;<br> audio_st = NULL;<br>
<br> if (fmt->video_codec != AV_CODEC_ID_NONE) {<br> video_st = add_stream(oc, &video_codec, fmt->video_codec);<br> }<br> if (fmt->audio_codec != AV_CODEC_ID_NONE) {<br> audio_st = add_stream(oc, &audio_codec, fmt->audio_codec);<br>
}<br><br> /* Now that all the parameters are set, we can open the audio and<br> * video codecs and allocate the necessary encode buffers. */<br> if (video_st)<br> open_video(oc, video_codec, video_st);<br>
if (audio_st)<br> open_audio(oc, audio_codec, audio_st);<br><br> av_dump_format(oc, 0, filename, 1);<br><br> /* open the output file, if needed */<br> if (!(fmt->flags & AVFMT_NOFILE)) {<br> if (avio_open(&oc->pb, filename, AVIO_FLAG_WRITE) < 0) {<br>
fprintf(stderr, "Could not open '%s'\n", filename);<br> return 1;<br> }<br> }<br><br> /* Write the stream header, if any. */<br> if (avformat_write_header(oc, NULL) < 0) {<br>
fprintf(stderr, "Error occurred when opening output file\n");<br> return 1;<br> }<br><br> if (frame)<br> frame->pts = 0;<br> for (;;) {<br> /* Compute current audio and video time. */<br>
if (audio_st)<br> audio_pts = (double)audio_st->pts.val * audio_st->time_base.num / audio_st->time_base.den;<br> else<br> audio_pts = 0.0;<br><br> if (video_st)<br> video_pts = (double)video_st->pts.val * video_st->time_base.num /<br>
video_st->time_base.den;<br> else<br> video_pts = 0.0;<br><br> if ((!audio_st || audio_pts >= STREAM_DURATION) &&<br> (!video_st || video_pts >= STREAM_DURATION))<br>
break;<br><br> /* write interleaved audio and video frames */<br> if (!video_st || (video_st && audio_st && audio_pts < video_pts)) {<br> write_audio_frame(oc, audio_st);<br>
} else {<br> write_video_frame(oc, video_st);<br> frame->pts += av_rescale_q(1, video_st->codec->time_base, video_st->time_base);<br> }<br> Sleep(40);<br> }<br><br>
/* Write the trailer, if any. The trailer must be written before you<br> * close the CodecContexts open when you wrote the header; otherwise<br> * av_write_trailer() may try to use memory that was freed on<br>
* av_codec_close(). */<br> av_write_trailer(oc);<br><br> /* Close each codec. */<br> if (video_st)<br> close_video(oc, video_st);<br> if (audio_st)<br> close_audio(oc, audio_st);<br><br> /* Free the streams. */<br>
for (i = 0; i < oc->nb_streams; i++) {<br> av_freep(&oc->streams[i]->codec);<br> av_freep(&oc->streams[i]);<br> }<br><br> if (!(fmt->flags & AVFMT_NOFILE))<br> /* Close the output file. */<br>
avio_close(oc->pb);<br><br> /* free the stream */<br> av_free(oc);<br><br> return 0;<br>}<br>*******************************************************************************<br><br>After first run, if we change<br>
<br>#define ENCODER_WIDTH 640<br>#define ENCODER_HEIGHT 480<br><br>to <br><br>#define ENCODER_WIDTH 160<br>#define ENCODER_HEIGHT 120<br><br>and
run again, file size is almost the same. Question now is why? shouldn't
smaller sized video be taking up much lesser space than the original
sized video?<br>
<br>Same thing happens if instead of saving to hard-disk I transmit over udp; it is taking up similar bandwidth consumption.<br><br>Can anyone provide guidance for above?<br><br>Thanks for your time!</div>