Newer
Older
/* if incorrect delay, use previous one */
delay = is->frame_last_delay;
is->frame_last_delay = delay;
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
is->frame_last_pts = frame_current_pts;
/* update delay to follow master synchronisation source */
if (((is->av_sync_type == AV_SYNC_AUDIO_MASTER && is->audio_st) ||
is->av_sync_type == AV_SYNC_EXTERNAL_CLOCK)) {
/* if video is slave, we try to correct big delays by
duplicating or deleting a frame */
ref_clock = get_master_clock(is);
diff = frame_current_pts - ref_clock;
/* skip or repeat frame. We take into account the
delay to compute the threshold. I still don't know
if it is the best guess */
sync_threshold = FFMAX(AV_SYNC_THRESHOLD, delay);
if (fabs(diff) < AV_NOSYNC_THRESHOLD) {
if (diff <= -sync_threshold)
delay = 0;
else if (diff >= sync_threshold)
delay = 2 * delay;
}
}
is->frame_timer += delay;
/* compute the REAL delay (we need to do that to avoid
long term errors */
actual_delay = is->frame_timer - (av_gettime() / 1000000.0);
if (actual_delay < 0.010) {
/* XXX: should skip picture */
actual_delay = 0.010;
}
#if defined(DEBUG_SYNC)
printf("video: delay=%0.3f actual_delay=%0.3f pts=%0.3f A-V=%f\n",
delay, actual_delay, frame_current_pts, -diff);
#endif
return actual_delay;
}
/* called to display each frame */
static void video_refresh_timer(void *opaque)
{
VideoState *is = opaque;
VideoPicture *vp;
Fabrice Bellard
committed
SubPicture *sp, *sp2;
if (is->video_st) {
if (is->pictq_size == 0) {
/* if no picture, need to wait */
Fabrice Bellard
committed
/* dequeue the picture */
Fabrice Bellard
committed
/* update current video pts */
is->video_current_pts = vp->pts;
is->video_current_pts_time = av_gettime();
schedule_refresh(is, (int)(compute_frame_delay(vp->pts, is) * 1000 + 0.5));
Fabrice Bellard
committed
if(is->subtitle_st) {
if (is->subtitle_stream_changed) {
SDL_LockMutex(is->subpq_mutex);
while (is->subpq_size) {
free_subpicture(&is->subpq[is->subpq_rindex]);
/* update queue size and signal for next picture */
if (++is->subpq_rindex == SUBPICTURE_QUEUE_SIZE)
is->subpq_rindex = 0;
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
is->subpq_size--;
}
is->subtitle_stream_changed = 0;
SDL_CondSignal(is->subpq_cond);
SDL_UnlockMutex(is->subpq_mutex);
} else {
if (is->subpq_size > 0) {
sp = &is->subpq[is->subpq_rindex];
if (is->subpq_size > 1)
sp2 = &is->subpq[(is->subpq_rindex + 1) % SUBPICTURE_QUEUE_SIZE];
else
sp2 = NULL;
if ((is->video_current_pts > (sp->pts + ((float) sp->sub.end_display_time / 1000)))
|| (sp2 && is->video_current_pts > (sp2->pts + ((float) sp2->sub.start_display_time / 1000))))
{
free_subpicture(sp);
/* update queue size and signal for next picture */
if (++is->subpq_rindex == SUBPICTURE_QUEUE_SIZE)
is->subpq_rindex = 0;
SDL_LockMutex(is->subpq_mutex);
is->subpq_size--;
SDL_CondSignal(is->subpq_cond);
SDL_UnlockMutex(is->subpq_mutex);
}
}
}
}
/* update queue size and signal for next picture */
if (++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE)
is->pictq_rindex = 0;
SDL_LockMutex(is->pictq_mutex);
is->pictq_size--;
SDL_CondSignal(is->pictq_cond);
SDL_UnlockMutex(is->pictq_mutex);
}
} else if (is->audio_st) {
/* draw the next audio frame */
schedule_refresh(is, 40);
/* if only audio stream, then display the audio bars (better
than nothing, just to test the implementation */
/* display picture */
video_display(is);
} else {
schedule_refresh(is, 100);
}
if (show_status) {
static int64_t last_time;
int64_t cur_time;
int aqsize, vqsize, sqsize;
Fabrice Bellard
committed
double av_diff;
if (!last_time || (cur_time - last_time) >= 30000) {
sqsize = 0;
if (is->audio_st)
aqsize = is->audioq.size;
if (is->video_st)
vqsize = is->videoq.size;
if (is->subtitle_st)
sqsize = is->subtitleq.size;
Fabrice Bellard
committed
av_diff = 0;
if (is->audio_st && is->video_st)
av_diff = get_audio_clock(is) - get_video_clock(is);
printf("%7.2f A-V:%7.3f aq=%5dKB vq=%5dKB sq=%5dB \r",
get_master_clock(is), av_diff, aqsize / 1024, vqsize / 1024, sqsize);
fflush(stdout);
last_time = cur_time;
}
}
}
/* allocate a picture (needs to do that in main thread to avoid
potential locking problems */
static void alloc_picture(void *opaque)
{
VideoState *is = opaque;
VideoPicture *vp;
vp = &is->pictq[is->pictq_windex];
if (vp->bmp)
SDL_FreeYUVOverlay(vp->bmp);
Michael Niedermayer
committed
vp->bmp = SDL_CreateYUVOverlay(is->video_st->codec->width,
is->video_st->codec->height,
Fabrice Bellard
committed
screen);
Michael Niedermayer
committed
vp->width = is->video_st->codec->width;
vp->height = is->video_st->codec->height;
SDL_LockMutex(is->pictq_mutex);
vp->allocated = 1;
SDL_CondSignal(is->pictq_cond);
SDL_UnlockMutex(is->pictq_mutex);
}
/**
*
* @param pts the dts of the pkt / pts of the frame and guessed if not known
*/
Fabrice Bellard
committed
static int queue_picture(VideoState *is, AVFrame *src_frame, double pts)
/* wait until we have space to put a new picture */
SDL_LockMutex(is->pictq_mutex);
while (is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE &&
!is->videoq.abort_request) {
SDL_CondWait(is->pictq_cond, is->pictq_mutex);
}
SDL_UnlockMutex(is->pictq_mutex);
if (is->videoq.abort_request)
return -1;
vp = &is->pictq[is->pictq_windex];
/* alloc or resize hardware picture buffer */
Michael Niedermayer
committed
vp->width != is->video_st->codec->width ||
vp->height != is->video_st->codec->height) {
SDL_Event event;
vp->allocated = 0;
/* the allocation must be done in the main thread to avoid
locking problems */
event.type = FF_ALLOC_EVENT;
event.user.data1 = is;
SDL_PushEvent(&event);
/* wait until the picture is allocated */
SDL_LockMutex(is->pictq_mutex);
while (!vp->allocated && !is->videoq.abort_request) {
SDL_CondWait(is->pictq_cond, is->pictq_mutex);
}
SDL_UnlockMutex(is->pictq_mutex);
if (is->videoq.abort_request)
return -1;
}
Fabrice Bellard
committed
/* if the frame is not skipped, then display it */
AVPicture pict;
/* get a pointer on the bitmap */
SDL_LockYUVOverlay (vp->bmp);
dst_pix_fmt = PIX_FMT_YUV420P;
memset(&pict,0,sizeof(AVPicture));
pict.data[0] = vp->bmp->pixels[0];
pict.data[1] = vp->bmp->pixels[2];
pict.data[2] = vp->bmp->pixels[1];
pict.linesize[0] = vp->bmp->pitches[0];
pict.linesize[1] = vp->bmp->pitches[2];
pict.linesize[2] = vp->bmp->pitches[1];
sws_flags = av_get_int(sws_opts, "sws_flags", NULL);
is->img_convert_ctx = sws_getCachedContext(is->img_convert_ctx,
is->video_st->codec->width, is->video_st->codec->height,
is->video_st->codec->pix_fmt,
is->video_st->codec->width, is->video_st->codec->height,
dst_pix_fmt, sws_flags, NULL, NULL, NULL);
if (is->img_convert_ctx == NULL) {
fprintf(stderr, "Cannot initialize the conversion context\n");
exit(1);
}
sws_scale(is->img_convert_ctx, src_frame->data, src_frame->linesize,
0, is->video_st->codec->height, pict.data, pict.linesize);
/* update the bitmap content */
SDL_UnlockYUVOverlay(vp->bmp);
Fabrice Bellard
committed
vp->pts = pts;
/* now we can update the picture count */
if (++is->pictq_windex == VIDEO_PICTURE_QUEUE_SIZE)
is->pictq_windex = 0;
SDL_LockMutex(is->pictq_mutex);
is->pictq_size++;
SDL_UnlockMutex(is->pictq_mutex);
}
Fabrice Bellard
committed
return 0;
}
/**
* compute the exact PTS for the picture if it is omitted in the stream
* @param pts1 the dts of the pkt / pts of the frame
*/
Fabrice Bellard
committed
static int output_picture2(VideoState *is, AVFrame *src_frame, double pts1)
{
double frame_delay, pts;
Fabrice Bellard
committed
pts = pts1;
Fabrice Bellard
committed
/* update video clock with pts, if present */
pts = is->video_clock;
}
/* update video clock for next frame */
Michael Niedermayer
committed
frame_delay = av_q2d(is->video_st->codec->time_base);
/* for MPEG2, the frame can be repeated, so we update the
clock accordingly */
frame_delay += src_frame->repeat_pict * (frame_delay * 0.5);
Fabrice Bellard
committed
#if defined(DEBUG_SYNC) && 0
{
int ftype;
if (src_frame->pict_type == FF_B_TYPE)
ftype = 'B';
else if (src_frame->pict_type == FF_I_TYPE)
ftype = 'I';
else
ftype = 'P';
printf("frame_type=%c clock=%0.3f pts=%0.3f\n",
Fabrice Bellard
committed
}
#endif
}
static int video_thread(void *arg)
{
VideoState *is = arg;
AVPacket pkt1, *pkt = &pkt1;
AVFrame *frame= avcodec_alloc_frame();
double pts;
for(;;) {
while (is->paused && !is->videoq.abort_request) {
SDL_Delay(10);
}
if (packet_queue_get(&is->videoq, pkt, 1) < 0)
break;
if(pkt->data == flush_pkt.data){
avcodec_flush_buffers(is->video_st->codec);
continue;
}
Fabrice Bellard
committed
/* NOTE: ipts is the PTS of the _first_ picture beginning in
this packet, if any */
is->video_st->codec->reordered_opaque= pkt->pts;
len1 = avcodec_decode_video2(is->video_st->codec,
if( (decoder_reorder_pts || pkt->dts == AV_NOPTS_VALUE)
&& frame->reordered_opaque != AV_NOPTS_VALUE)
pts= frame->reordered_opaque;
else if(pkt->dts != AV_NOPTS_VALUE)
pts= pkt->dts;
else
pts= 0;
pts *= av_q2d(is->video_st->time_base);
Michael Niedermayer
committed
if (got_picture) {
if (output_picture2(is, frame, pts) < 0)
goto the_end;
}
Wolfgang Hesseler
committed
if (cur_stream)
stream_pause(cur_stream);
static int subtitle_thread(void *arg)
{
VideoState *is = arg;
SubPicture *sp;
AVPacket pkt1, *pkt = &pkt1;
int len1, got_subtitle;
double pts;
int i, j;
int r, g, b, y, u, v, a;
for(;;) {
while (is->paused && !is->subtitleq.abort_request) {
SDL_Delay(10);
}
if (packet_queue_get(&is->subtitleq, pkt, 1) < 0)
break;
if(pkt->data == flush_pkt.data){
avcodec_flush_buffers(is->subtitle_st->codec);
continue;
}
SDL_LockMutex(is->subpq_mutex);
while (is->subpq_size >= SUBPICTURE_QUEUE_SIZE &&
!is->subtitleq.abort_request) {
SDL_CondWait(is->subpq_cond, is->subpq_mutex);
}
SDL_UnlockMutex(is->subpq_mutex);
if (is->subtitleq.abort_request)
goto the_end;
sp = &is->subpq[is->subpq_windex];
/* NOTE: ipts is the PTS of the _first_ picture beginning in
this packet, if any */
pts = 0;
if (pkt->pts != AV_NOPTS_VALUE)
pts = av_q2d(is->subtitle_st->time_base)*pkt->pts;
len1 = avcodec_decode_subtitle2(is->subtitle_st->codec,
// if (len1 < 0)
// break;
if (got_subtitle && sp->sub.format == 0) {
sp->pts = pts;
for (i = 0; i < sp->sub.num_rects; i++)
{
for (j = 0; j < sp->sub.rects[i]->nb_colors; j++)
{
RGBA_IN(r, g, b, a, (uint32_t*)sp->sub.rects[i]->pict.data[1] + j);
y = RGB_TO_Y_CCIR(r, g, b);
u = RGB_TO_U_CCIR(r, g, b, 0);
v = RGB_TO_V_CCIR(r, g, b, 0);
YUVA_OUT((uint32_t*)sp->sub.rects[i]->pict.data[1] + j, y, u, v, a);
}
}
/* now we can update the picture count */
if (++is->subpq_windex == SUBPICTURE_QUEUE_SIZE)
is->subpq_windex = 0;
SDL_LockMutex(is->subpq_mutex);
is->subpq_size++;
SDL_UnlockMutex(is->subpq_mutex);
}
av_free_packet(pkt);
// if (cur_stream)
// stream_pause(cur_stream);
}
the_end:
return 0;
}
/* copy samples for viewing in editor window */
static void update_sample_display(VideoState *is, short *samples, int samples_size)
{
int size, len, channels;
Michael Niedermayer
committed
channels = is->audio_st->codec->channels;
size = samples_size / sizeof(short);
while (size > 0) {
len = SAMPLE_ARRAY_SIZE - is->sample_array_index;
if (len > size)
len = size;
memcpy(is->sample_array + is->sample_array_index, samples, len * sizeof(short));
samples += len;
is->sample_array_index += len;
if (is->sample_array_index >= SAMPLE_ARRAY_SIZE)
is->sample_array_index = 0;
size -= len;
}
}
/* return the new audio buffer size (samples can be added or deleted
to get better sync if video or external master clock) */
static int synchronize_audio(VideoState *is, short *samples,
Fabrice Bellard
committed
int samples_size1, double pts)
Fabrice Bellard
committed
int n, samples_size;
Michael Niedermayer
committed
n = 2 * is->audio_st->codec->channels;
Fabrice Bellard
committed
samples_size = samples_size1;
/* if not master, then we try to remove or add samples to correct the clock */
if (((is->av_sync_type == AV_SYNC_VIDEO_MASTER && is->video_st) ||
Fabrice Bellard
committed
is->av_sync_type == AV_SYNC_EXTERNAL_CLOCK)) {
double diff, avg_diff;
int wanted_size, min_size, max_size, nb_samples;
Fabrice Bellard
committed
ref_clock = get_master_clock(is);
diff = get_audio_clock(is) - ref_clock;
Fabrice Bellard
committed
if (diff < AV_NOSYNC_THRESHOLD) {
is->audio_diff_cum = diff + is->audio_diff_avg_coef * is->audio_diff_cum;
if (is->audio_diff_avg_count < AUDIO_DIFF_AVG_NB) {
/* not enough measures to have a correct estimate */
is->audio_diff_avg_count++;
} else {
/* estimate the A-V difference */
avg_diff = is->audio_diff_cum * (1.0 - is->audio_diff_avg_coef);
if (fabs(avg_diff) >= is->audio_diff_threshold) {
Michael Niedermayer
committed
wanted_size = samples_size + ((int)(diff * is->audio_st->codec->sample_rate) * n);
Fabrice Bellard
committed
nb_samples = samples_size / n;
Fabrice Bellard
committed
min_size = ((nb_samples * (100 - SAMPLE_CORRECTION_PERCENT_MAX)) / 100) * n;
max_size = ((nb_samples * (100 + SAMPLE_CORRECTION_PERCENT_MAX)) / 100) * n;
if (wanted_size < min_size)
wanted_size = min_size;
else if (wanted_size > max_size)
wanted_size = max_size;
Fabrice Bellard
committed
/* add or remove samples to correction the synchro */
if (wanted_size < samples_size) {
/* remove samples */
samples_size = wanted_size;
} else if (wanted_size > samples_size) {
uint8_t *samples_end, *q;
int nb;
Fabrice Bellard
committed
/* add samples */
nb = (samples_size - wanted_size);
samples_end = (uint8_t *)samples + samples_size - n;
q = samples_end + n;
while (nb > 0) {
memcpy(q, samples_end, n);
q += n;
nb -= n;
}
samples_size = wanted_size;
}
}
#if 0
printf("diff=%f adiff=%f sample_diff=%d apts=%0.3f vpts=%0.3f %f\n",
diff, avg_diff, samples_size - samples_size1,
Fabrice Bellard
committed
is->audio_clock, is->video_clock, is->audio_diff_threshold);
#endif
Fabrice Bellard
committed
} else {
/* too big difference : may be initial PTS errors, so
reset A-V filter */
is->audio_diff_avg_count = 0;
is->audio_diff_cum = 0;
}
}
return samples_size;
}
/* decode one audio frame and returns its uncompressed size */
static int audio_decode_frame(VideoState *is, double *pts_ptr)
AVPacket *pkt_temp = &is->audio_pkt_temp;
AVCodecContext *dec= is->audio_st->codec;
/* NOTE: the audio packet can contain several frames */
data_size = sizeof(is->audio_buf1);
(int16_t *)is->audio_buf1, &data_size,
if (len1 < 0) {
/* if error, we skip the frame */
pkt_temp->data += len1;
pkt_temp->size -= len1;
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
if (dec->sample_fmt != is->audio_src_fmt) {
if (is->reformat_ctx)
av_audio_convert_free(is->reformat_ctx);
is->reformat_ctx= av_audio_convert_alloc(SAMPLE_FMT_S16, 1,
dec->sample_fmt, 1, NULL, 0);
if (!is->reformat_ctx) {
fprintf(stderr, "Cannot convert %s sample format to %s sample format\n",
avcodec_get_sample_fmt_name(dec->sample_fmt),
avcodec_get_sample_fmt_name(SAMPLE_FMT_S16));
break;
}
is->audio_src_fmt= dec->sample_fmt;
}
if (is->reformat_ctx) {
const void *ibuf[6]= {is->audio_buf1};
void *obuf[6]= {is->audio_buf2};
int istride[6]= {av_get_bits_per_sample_format(dec->sample_fmt)/8};
int ostride[6]= {2};
int len= data_size/istride[0];
if (av_audio_convert(is->reformat_ctx, obuf, ostride, ibuf, istride, len)<0) {
printf("av_audio_convert() failed\n");
break;
}
is->audio_buf= is->audio_buf2;
/* FIXME: existing code assume that data_size equals framesize*channels*2
remove this legacy cruft */
data_size= len*2;
}else{
is->audio_buf= is->audio_buf1;
}
/* if no pts, then compute it */
pts = is->audio_clock;
*pts_ptr = pts;
n = 2 * dec->channels;
is->audio_clock += (double)data_size /
(double)(n * dec->sample_rate);
Fabrice Bellard
committed
#if defined(DEBUG_SYNC)
{
static double last_clock;
printf("audio: delay=%0.3f clock=%0.3f pts=%0.3f\n",
is->audio_clock - last_clock,
is->audio_clock, pts);
last_clock = is->audio_clock;
/* free the current packet */
if (pkt->data)
if (is->paused || is->audioq.abort_request) {
return -1;
}
/* read next packet */
if (packet_queue_get(&is->audioq, pkt, 1) < 0)
return -1;
if(pkt->data == flush_pkt.data){
avcodec_flush_buffers(dec);
pkt_temp->data = pkt->data;
pkt_temp->size = pkt->size;
/* if update the audio clock with the pts */
if (pkt->pts != AV_NOPTS_VALUE) {
is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts;
Fabrice Bellard
committed
/* get the current audio output buffer size, in samples. With SDL, we
cannot have a precise information */
static int audio_write_get_buf_size(VideoState *is)
return is->audio_buf_size - is->audio_buf_index;
}
/* prepare a new audio buffer */
Diego Pettenò
committed
static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
{
VideoState *is = opaque;
int audio_size, len1;
double pts;
audio_callback_time = av_gettime();
while (len > 0) {
if (is->audio_buf_index >= is->audio_buf_size) {
audio_size = audio_decode_frame(is, &pts);
if (audio_size < 0) {
/* if error, just output silence */
is->audio_buf = is->audio_buf1;
is->audio_buf_size = 1024;
memset(is->audio_buf, 0, is->audio_buf_size);
} else {
if (is->show_audio)
update_sample_display(is, (int16_t *)is->audio_buf, audio_size);
audio_size = synchronize_audio(is, (int16_t *)is->audio_buf, audio_size,
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
pts);
is->audio_buf_size = audio_size;
}
is->audio_buf_index = 0;
}
len1 = is->audio_buf_size - is->audio_buf_index;
if (len1 > len)
len1 = len;
memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1);
len -= len1;
stream += len1;
is->audio_buf_index += len1;
}
}
/* open a given stream. Return 0 if OK */
static int stream_component_open(VideoState *is, int stream_index)
{
AVFormatContext *ic = is->ic;
AVCodecContext *enc;
AVCodec *codec;
SDL_AudioSpec wanted_spec, spec;
if (stream_index < 0 || stream_index >= ic->nb_streams)
return -1;
Michael Niedermayer
committed
enc = ic->streams[stream_index]->codec;
/* prepare audio output */
if (enc->codec_type == CODEC_TYPE_AUDIO) {
if (enc->channels > 0) {
enc->request_channels = FFMIN(2, enc->channels);
enc->request_channels = 2;
Fabrice Bellard
committed
}
}
codec = avcodec_find_decoder(enc->codec_id);
enc->debug_mv = debug_mv;
enc->debug = debug;
if(lowres) enc->flags |= CODEC_FLAG_EMU_EDGE;
if(fast) enc->flags2 |= CODEC_FLAG2_FAST;
enc->skip_frame= skip_frame;
enc->skip_idct= skip_idct;
enc->skip_loop_filter= skip_loop_filter;
enc->error_recognition= error_recognition;
Michael Niedermayer
committed
enc->error_concealment= error_concealment;
set_context_opts(enc, avcodec_opts[enc->codec_type], 0);
if (!codec ||
avcodec_open(enc, codec) < 0)
return -1;
/* prepare audio output */
if (enc->codec_type == CODEC_TYPE_AUDIO) {
wanted_spec.freq = enc->sample_rate;
wanted_spec.format = AUDIO_S16SYS;
wanted_spec.channels = enc->channels;
wanted_spec.silence = 0;
wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;
wanted_spec.callback = sdl_audio_callback;
wanted_spec.userdata = is;
if (SDL_OpenAudio(&wanted_spec, &spec) < 0) {
fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError());
return -1;
}
is->audio_hw_buf_size = spec.size;
}
Ronald S. Bultje
committed
ic->streams[stream_index]->discard = AVDISCARD_DEFAULT;
Fabrice Bellard
committed
switch(enc->codec_type) {
case CODEC_TYPE_AUDIO:
is->audio_stream = stream_index;
is->audio_st = ic->streams[stream_index];
is->audio_buf_size = 0;
is->audio_buf_index = 0;
Fabrice Bellard
committed
/* init averaging filter */
is->audio_diff_avg_coef = exp(log(0.01) / AUDIO_DIFF_AVG_NB);
is->audio_diff_avg_count = 0;
/* since we do not have a precise anough audio fifo fullness,
we correct audio sync only if larger than this threshold */
is->audio_diff_threshold = 2.0 * SDL_AUDIO_BUFFER_SIZE / enc->sample_rate;
memset(&is->audio_pkt, 0, sizeof(is->audio_pkt));
packet_queue_init(&is->audioq);
break;
case CODEC_TYPE_VIDEO:
is->video_stream = stream_index;
is->video_st = ic->streams[stream_index];
Fabrice Bellard
committed
is->frame_last_delay = 40e-3;
is->frame_timer = (double)av_gettime() / 1000000.0;
is->video_current_pts_time = av_gettime();
packet_queue_init(&is->videoq);
is->video_tid = SDL_CreateThread(video_thread, is);
break;
case CODEC_TYPE_SUBTITLE:
is->subtitle_stream = stream_index;
is->subtitle_st = ic->streams[stream_index];
packet_queue_init(&is->subtitleq);
is->subtitle_tid = SDL_CreateThread(subtitle_thread, is);
break;
default:
break;
}
return 0;
}
static void stream_component_close(VideoState *is, int stream_index)
{
AVFormatContext *ic = is->ic;
AVCodecContext *enc;
if (stream_index < 0 || stream_index >= ic->nb_streams)
return;
Michael Niedermayer
committed
enc = ic->streams[stream_index]->codec;
switch(enc->codec_type) {
case CODEC_TYPE_AUDIO:
packet_queue_abort(&is->audioq);
SDL_CloseAudio();
packet_queue_end(&is->audioq);
if (is->reformat_ctx)
av_audio_convert_free(is->reformat_ctx);
break;
case CODEC_TYPE_VIDEO:
packet_queue_abort(&is->videoq);
/* note: we also signal this mutex to make sure we deblock the
video thread in all cases */
SDL_LockMutex(is->pictq_mutex);
SDL_CondSignal(is->pictq_cond);
SDL_UnlockMutex(is->pictq_mutex);
SDL_WaitThread(is->video_tid, NULL);
packet_queue_end(&is->videoq);
break;
case CODEC_TYPE_SUBTITLE:
packet_queue_abort(&is->subtitleq);
/* note: we also signal this mutex to make sure we deblock the
video thread in all cases */
SDL_LockMutex(is->subpq_mutex);
is->subtitle_stream_changed = 1;
SDL_CondSignal(is->subpq_cond);
SDL_UnlockMutex(is->subpq_mutex);
SDL_WaitThread(is->subtitle_tid, NULL);
packet_queue_end(&is->subtitleq);
break;
Ronald S. Bultje
committed
ic->streams[stream_index]->discard = AVDISCARD_ALL;
avcodec_close(enc);
switch(enc->codec_type) {
case CODEC_TYPE_AUDIO:
is->audio_st = NULL;
is->audio_stream = -1;
break;
case CODEC_TYPE_VIDEO:
is->video_st = NULL;
is->video_stream = -1;
break;
case CODEC_TYPE_SUBTITLE:
is->subtitle_st = NULL;
is->subtitle_stream = -1;
break;
Fabrice Bellard
committed
/* since we have only one decoding thread, we can use a global
variable instead of a thread local variable */
static VideoState *global_video_state;
static int decode_interrupt_cb(void)
{
return (global_video_state && global_video_state->abort_request);
}
/* this thread gets the stream from the disk or the network */
static int decode_thread(void *arg)
{
VideoState *is = arg;
AVFormatContext *ic;
int err, i, ret, video_index, audio_index, subtitle_index;
Fabrice Bellard
committed
AVFormatParameters params, *ap = ¶ms;
subtitle_index = -1;
is->video_stream = -1;
is->audio_stream = -1;
is->subtitle_stream = -1;
Fabrice Bellard
committed
global_video_state = is;
url_set_interrupt_cb(decode_interrupt_cb);
Fabrice Bellard
committed
memset(ap, 0, sizeof(*ap));
Limin Wang
committed
ap->width = frame_width;
ap->height= frame_height;
Limin Wang
committed
ap->pix_fmt = frame_pix_fmt;
Fabrice Bellard
committed
err = av_open_input_file(&ic, is->filename, is->iformat, 0, ap);
Fabrice Bellard
committed
if (err < 0) {
print_error(is->filename, err);
ret = -1;
goto fail;
}
if(genpts)
ic->flags |= AVFMT_FLAG_GENPTS;
err = av_find_stream_info(ic);
if (err < 0) {
fprintf(stderr, "%s: could not find codec parameters\n", is->filename);
ret = -1;
goto fail;
}
if(ic->pb)
ic->pb->eof_reached= 0; //FIXME hack, ffplay maybe should not use url_feof() to test for the end
/* if seeking requested, we execute it */
if (start_time != AV_NOPTS_VALUE) {
int64_t timestamp;
timestamp = start_time;
/* add the stream start time */
if (ic->start_time != AV_NOPTS_VALUE)
timestamp += ic->start_time;
ret = avformat_seek_file(ic, -1, INT64_MIN, timestamp, INT64_MAX, 0);
fprintf(stderr, "%s: could not seek to position %0.3f\n",
is->filename, (double)timestamp / AV_TIME_BASE);
}
}
Michael Niedermayer
committed
AVCodecContext *enc = ic->streams[i]->codec;
Ronald S. Bultje
committed
ic->streams[i]->discard = AVDISCARD_ALL;
switch(enc->codec_type) {
case CODEC_TYPE_AUDIO:
Stefano Sabatini
committed
if (wanted_audio_stream-- >= 0 && !audio_disable)
audio_index = i;
break;
case CODEC_TYPE_VIDEO:
Stefano Sabatini
committed
if (wanted_video_stream-- >= 0 && !video_disable)
case CODEC_TYPE_SUBTITLE:
if (wanted_subtitle_stream-- >= 0 && !video_disable)
subtitle_index = i;
break;
default:
break;
}
}
if (show_status) {
dump_format(ic, 0, is->filename, 0);
}
/* open the streams */
if (audio_index >= 0) {
stream_component_open(is, audio_index);
}
if (video_index >= 0) {
stream_component_open(is, video_index);
} else {
if (!display_disable)
is->show_audio = 1;
}
if (subtitle_index >= 0) {
stream_component_open(is, subtitle_index);
}
if (is->video_stream < 0 && is->audio_stream < 0) {
Fabrice Bellard
committed
fprintf(stderr, "%s: could not open codecs\n", is->filename);
ret = -1;
goto fail;
}
for(;;) {
if (is->abort_request)
break;
Fabrice Bellard
committed
if (is->paused != is->last_paused) {
is->last_paused = is->paused;
if (is->paused)
av_read_pause(ic);
else
av_read_play(ic);
Fabrice Bellard
committed
}
#if CONFIG_RTSP_DEMUXER
if (is->paused && !strcmp(ic->iformat->name, "rtsp")) {
Fabrice Bellard
committed
/* wait 10 ms to avoid trying to get another packet */
/* XXX: horrible */
SDL_Delay(10);
continue;
}
Michael Niedermayer
committed
#endif
Michael Niedermayer
committed
int64_t seek_target= is->seek_pos;