2 * This file is part of MPlayer.
4 * MPlayer is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * MPlayer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include <sys/types.h>
29 #include "aviheader.h"
33 #include "stream/stream.h"
38 #include "libavformat/avformat.h"
39 #include "libavutil/avstring.h"
41 #include "mp_taglists.h"
43 enum PixelFormat
imgfmt2pixfmt(int fmt
);
45 extern char *info_name
;
46 extern char *info_artist
;
47 extern char *info_genre
;
48 extern char *info_subject
;
49 extern char *info_copyright
;
50 extern char *info_sourceform
;
51 extern char *info_comment
;
53 #define BIO_BUFFER_SIZE 32768
56 //AVInputFormat *avif;
62 uint8_t buffer
[BIO_BUFFER_SIZE
];
68 } muxer_stream_priv_t
;
70 static char *conf_format
= NULL
;
71 static int mux_rate
= 0;
72 static int mux_packet_size
= 0;
73 static float mux_preload
= 0.5;
74 static float mux_max_delay
= 0.7;
75 static char *mux_avopt
= NULL
;
77 m_option_t lavfopts_conf
[] = {
78 {"format", &(conf_format
), CONF_TYPE_STRING
, 0, 0, 0, NULL
},
79 {"muxrate", &mux_rate
, CONF_TYPE_INT
, CONF_RANGE
, 0, INT_MAX
, NULL
},
80 {"packetsize", &mux_packet_size
, CONF_TYPE_INT
, CONF_RANGE
, 0, INT_MAX
, NULL
},
81 {"preload", &mux_preload
, CONF_TYPE_FLOAT
, CONF_RANGE
, 0, INT_MAX
, NULL
},
82 {"delay", &mux_max_delay
, CONF_TYPE_FLOAT
, CONF_RANGE
, 0, INT_MAX
, NULL
},
83 {"o", &mux_avopt
, CONF_TYPE_STRING
, 0, 0, 0, NULL
},
85 {NULL
, NULL
, 0, 0, 0, 0, NULL
}
88 static int mp_write(void *opaque
, uint8_t *buf
, int size
)
90 muxer_t
*muxer
= opaque
;
91 return stream_write_buffer(muxer
->stream
, buf
, size
);
94 static int64_t mp_seek(void *opaque
, int64_t pos
, int whence
)
96 muxer_t
*muxer
= opaque
;
97 if(whence
== SEEK_CUR
)
99 off_t cur
= stream_tell(muxer
->stream
);
104 else if(whence
== SEEK_END
)
107 if(stream_control(muxer
->stream
, STREAM_CTRL_GET_SIZE
, &size
) == STREAM_UNSUPPORTED
|| size
< pos
)
111 mp_msg(MSGT_MUXER
, MSGL_DBG2
, "SEEK %"PRIu64
"\n", (int64_t)pos
);
112 if(!stream_seek(muxer
->stream
, pos
))
118 static muxer_stream_t
* lavf_new_stream(muxer_t
*muxer
, int type
)
120 muxer_priv_t
*priv
= muxer
->priv
;
121 muxer_stream_t
*stream
;
122 muxer_stream_priv_t
*spriv
;
125 if(!muxer
|| (type
!= MUXER_TYPE_VIDEO
&& type
!= MUXER_TYPE_AUDIO
))
127 mp_msg(MSGT_MUXER
, MSGL_ERR
, "UNKNOWN TYPE %d\n", type
);
131 stream
= calloc(1, sizeof(muxer_stream_t
));
134 mp_msg(MSGT_MUXER
, MSGL_ERR
, "Could not allocate muxer_stream, EXIT.\n");
137 muxer
->streams
[muxer
->avih
.dwStreams
] = stream
;
138 stream
->b_buffer
= malloc(2048);
139 if(!stream
->b_buffer
)
141 mp_msg(MSGT_MUXER
, MSGL_ERR
, "Could not allocate b_buffer, EXIT.\n");
145 stream
->b_buffer_size
= 2048;
146 stream
->b_buffer_ptr
= 0;
147 stream
->b_buffer_len
= 0;
149 spriv
= calloc(1, sizeof(muxer_stream_priv_t
));
155 stream
->priv
= spriv
;
157 spriv
->avstream
= av_new_stream(priv
->oc
, 1);
160 mp_msg(MSGT_MUXER
, MSGL_ERR
, "Could not allocate avstream, EXIT.\n");
163 spriv
->avstream
->stream_copy
= 1;
165 ctx
= spriv
->avstream
->codec
;
166 ctx
->codec_id
= muxer
->avih
.dwStreams
;
169 case MUXER_TYPE_VIDEO
:
170 ctx
->codec_type
= CODEC_TYPE_VIDEO
;
172 case MUXER_TYPE_AUDIO
:
173 ctx
->codec_type
= CODEC_TYPE_AUDIO
;
177 muxer
->avih
.dwStreams
++;
178 stream
->muxer
= muxer
;
180 mp_msg(MSGT_MUXER
, MSGL_V
, "ALLOCATED STREAM N. %d, type=%d\n", muxer
->avih
.dwStreams
, type
);
185 static void fix_parameters(muxer_stream_t
*stream
)
187 muxer_stream_priv_t
*spriv
= (muxer_stream_priv_t
*) stream
->priv
;
190 ctx
= spriv
->avstream
->codec
;
192 ctx
->bit_rate
= stream
->avg_rate
;
193 if(stream
->wf
&& stream
->wf
->nAvgBytesPerSec
&& !ctx
->bit_rate
)
194 ctx
->bit_rate
= stream
->wf
->nAvgBytesPerSec
* 8;
195 ctx
->rc_buffer_size
= stream
->vbv_size
;
196 ctx
->rc_max_rate
= stream
->max_rate
;
198 if(stream
->type
== MUXER_TYPE_AUDIO
)
200 ctx
->codec_id
= av_codec_get_id(mp_wav_taglists
, stream
->wf
->wFormatTag
);
201 #if 0 //breaks aac in mov at least
202 ctx
->codec_tag
= codec_get_wav_tag(ctx
->codec_id
);
204 mp_msg(MSGT_MUXER
, MSGL_INFO
, "AUDIO CODEC ID: %x, TAG: %x\n", ctx
->codec_id
, (uint32_t) ctx
->codec_tag
);
205 ctx
->sample_rate
= stream
->wf
->nSamplesPerSec
;
206 // mp_msg(MSGT_MUXER, MSGL_INFO, "stream->h.dwSampleSize: %d\n", stream->h.dwSampleSize);
207 ctx
->channels
= stream
->wf
->nChannels
;
208 if(stream
->h
.dwRate
&& (stream
->h
.dwScale
* (int64_t)ctx
->sample_rate
) % stream
->h
.dwRate
== 0)
209 ctx
->frame_size
= (stream
->h
.dwScale
* (int64_t)ctx
->sample_rate
) / stream
->h
.dwRate
;
210 mp_msg(MSGT_MUXER
, MSGL_V
, "MUXER_LAVF(audio stream) frame_size: %d, scale: %u, sps: %u, rate: %u, ctx->block_align = stream->wf->nBlockAlign; %d=%d stream->wf->nAvgBytesPerSec:%d\n",
211 ctx
->frame_size
, stream
->h
.dwScale
, ctx
->sample_rate
, stream
->h
.dwRate
,
212 ctx
->block_align
, stream
->wf
->nBlockAlign
, stream
->wf
->nAvgBytesPerSec
);
213 ctx
->block_align
= stream
->h
.dwSampleSize
;
214 if(stream
->wf
+1 && stream
->wf
->cbSize
)
216 ctx
->extradata
= av_malloc(stream
->wf
->cbSize
);
217 if(ctx
->extradata
!= NULL
)
219 ctx
->extradata_size
= stream
->wf
->cbSize
;
220 memcpy(ctx
->extradata
, stream
->wf
+1, ctx
->extradata_size
);
223 mp_msg(MSGT_MUXER
, MSGL_ERR
, "MUXER_LAVF(audio stream) error! Could not allocate %d bytes for extradata.\n",
227 else if(stream
->type
== MUXER_TYPE_VIDEO
)
229 ctx
->codec_id
= av_codec_get_id(mp_bmp_taglists
, stream
->bih
->biCompression
);
230 if(ctx
->codec_id
<= 0 || force_fourcc
)
231 ctx
->codec_tag
= stream
->bih
->biCompression
;
232 mp_msg(MSGT_MUXER
, MSGL_INFO
, "VIDEO CODEC ID: %d\n", ctx
->codec_id
);
234 ctx
->pix_fmt
= imgfmt2pixfmt(stream
->imgfmt
);
235 ctx
->width
= stream
->bih
->biWidth
;
236 ctx
->height
= stream
->bih
->biHeight
;
237 ctx
->bit_rate
= 800000;
238 ctx
->time_base
.den
= stream
->h
.dwRate
;
239 ctx
->time_base
.num
= stream
->h
.dwScale
;
240 if(stream
->bih
+1 && (stream
->bih
->biSize
> sizeof(BITMAPINFOHEADER
)))
242 ctx
->extradata_size
= stream
->bih
->biSize
- sizeof(BITMAPINFOHEADER
);
243 ctx
->extradata
= av_malloc(ctx
->extradata_size
);
244 if(ctx
->extradata
!= NULL
)
245 memcpy(ctx
->extradata
, stream
->bih
+1, ctx
->extradata_size
);
248 mp_msg(MSGT_MUXER
, MSGL_ERR
, "MUXER_LAVF(video stream) error! Could not allocate %d bytes for extradata.\n",
249 ctx
->extradata_size
);
250 ctx
->extradata_size
= 0;
256 static void write_chunk(muxer_stream_t
*stream
, size_t len
, unsigned int flags
, double dts
, double pts
)
258 muxer_t
*muxer
= (muxer_t
*) stream
->muxer
;
259 muxer_priv_t
*priv
= (muxer_priv_t
*) muxer
->priv
;
260 muxer_stream_priv_t
*spriv
= (muxer_stream_priv_t
*) stream
->priv
;
265 av_init_packet(&pkt
);
267 pkt
.stream_index
= spriv
->avstream
->index
;
268 pkt
.data
= stream
->buffer
;
270 if(flags
& AVIIF_KEYFRAME
)
271 pkt
.flags
|= PKT_FLAG_KEY
;
275 pkt
.dts
= (dts
/ av_q2d(priv
->oc
->streams
[pkt
.stream_index
]->time_base
) + 0.5);
276 pkt
.pts
= (pts
/ av_q2d(priv
->oc
->streams
[pkt
.stream_index
]->time_base
) + 0.5);
277 //fprintf(stderr, "%Ld %Ld id:%d tb:%f %f\n", pkt.dts, pkt.pts, pkt.stream_index, av_q2d(priv->oc->streams[pkt.stream_index]->time_base), stream->timer);
279 if(av_interleaved_write_frame(priv
->oc
, &pkt
) != 0) //av_write_frame(priv->oc, &pkt)
281 mp_msg(MSGT_MUXER
, MSGL_ERR
, "Error while writing frame.\n");
289 static void write_header(muxer_t
*muxer
)
291 muxer_priv_t
*priv
= (muxer_priv_t
*) muxer
->priv
;
293 mp_msg(MSGT_MUXER
, MSGL_INFO
, MSGTR_WritingHeader
);
294 av_write_header(priv
->oc
);
295 muxer
->cont_write_header
= NULL
;
299 static void write_trailer(muxer_t
*muxer
)
302 muxer_priv_t
*priv
= (muxer_priv_t
*) muxer
->priv
;
304 mp_msg(MSGT_MUXER
, MSGL_INFO
, MSGTR_WritingTrailer
);
305 av_write_trailer(priv
->oc
);
306 for(i
= 0; i
< priv
->oc
->nb_streams
; i
++)
308 av_freep(&(priv
->oc
->streams
[i
]));
311 av_freep(&priv
->oc
->pb
);
316 static void list_formats(void) {
318 mp_msg(MSGT_DEMUX
, MSGL_INFO
, "Available lavf output formats:\n");
319 for (fmt
= first_oformat
; fmt
; fmt
= fmt
->next
)
320 mp_msg(MSGT_DEMUX
, MSGL_INFO
, "%15s : %s\n", fmt
->name
, fmt
->long_name
);
323 extern char *out_filename
;
324 int muxer_init_muxer_lavf(muxer_t
*muxer
)
327 AVOutputFormat
*fmt
= NULL
;
331 if (conf_format
&& strcmp(conf_format
, "help") == 0) {
336 mp_msg(MSGT_MUXER
, MSGL_WARN
, "** MUXER_LAVF *****************************************************************\n");
337 mp_msg(MSGT_MUXER
, MSGL_WARN
,
338 "REMEMBER: MEncoder's libavformat muxing is presently broken and can generate\n"
339 "INCORRECT files in the presence of B-frames. Moreover, due to bugs MPlayer\n"
340 "will play these INCORRECT files as if nothing were wrong!\n"
341 "*******************************************************************************\n");
343 priv
= (muxer_priv_t
*) calloc(1, sizeof(muxer_priv_t
));
347 priv
->oc
= av_alloc_format_context();
350 mp_msg(MSGT_MUXER
, MSGL_FATAL
, "Could not get format context.\n");
355 fmt
= guess_format(conf_format
, NULL
, NULL
);
357 fmt
= guess_format(NULL
, out_filename
, NULL
);
360 mp_msg(MSGT_MUXER
, MSGL_FATAL
, "Cannot get specified format.\n");
363 priv
->oc
->oformat
= fmt
;
366 if(av_set_parameters(priv
->oc
, NULL
) < 0)
368 mp_msg(MSGT_MUXER
, MSGL_FATAL
, "invalid output format parameters\n");
371 priv
->oc
->packet_size
= mux_packet_size
;
372 priv
->oc
->mux_rate
= mux_rate
;
373 priv
->oc
->preload
= (int)(mux_preload
*AV_TIME_BASE
);
374 priv
->oc
->max_delay
= (int)(mux_max_delay
*AV_TIME_BASE
);
376 av_strlcpy(priv
->oc
->title
, info_name
, sizeof(priv
->oc
->title
));
378 av_strlcpy(priv
->oc
->author
, info_artist
, sizeof(priv
->oc
->author
));
380 av_strlcpy(priv
->oc
->genre
, info_genre
, sizeof(priv
->oc
->genre
));
382 av_strlcpy(priv
->oc
->copyright
, info_copyright
, sizeof(priv
->oc
->copyright
));
384 av_strlcpy(priv
->oc
->comment
, info_comment
, sizeof(priv
->oc
->comment
));
387 if(parse_avopts(priv
->oc
, mux_avopt
) < 0){
388 mp_msg(MSGT_MUXER
,MSGL_ERR
, "Your options /%s/ look like gibberish to me pal.\n", mux_avopt
);
393 priv
->oc
->pb
= av_alloc_put_byte(priv
->buffer
, BIO_BUFFER_SIZE
, 1, muxer
, NULL
, mp_write
, mp_seek
);
394 if ((muxer
->stream
->flags
& STREAM_SEEK
) != STREAM_SEEK
)
395 priv
->oc
->pb
->is_streamed
= 1;
397 muxer
->priv
= (void *) priv
;
398 muxer
->cont_new_stream
= &lavf_new_stream
;
399 muxer
->cont_write_chunk
= &write_chunk
;
400 muxer
->cont_write_header
= &write_header
;
401 muxer
->cont_write_index
= &write_trailer
;
402 muxer
->fix_stream_parameters
= &fix_parameters
;
403 mp_msg(MSGT_MUXER
, MSGL_INFO
, "OK, exit.\n");