AVDecoder.cpp 4.1 KB
#include "AVDecoder.h"
extern "C" {
#include <libswscale/swscale.h> 
}

CAVDecoder::CAVDecoder() :
_a_start_time_ms(INT64_MAX),
_v_start_time_ms(INT64_MAX),
_cur_a_ts_ms(INT64_MAX),
_cur_v_ts_ms(INT64_MAX),
_end_time_ms(0),
_cur_a_frame(NULL),
_cur_v_frame(NULL),
_media_role(mr_student),
_scaled_width(0),
_scaled_height(0),
_src_width(0),
_src_height(0),
_sws_ctx(NULL)
{
}


CAVDecoder::~CAVDecoder()
{
	free_cur_v_frame();
	free_cur_a_frame();
	if (_sws_ctx) {
		sws_freeContext(_sws_ctx);
		_sws_ctx = NULL;
	}
}

int CAVDecoder::add(media_info &info)
{
	_media_role = info.m_role;
	_uid = info.uid;
	if (info.m_type == mt_audio) {
		_a_start_time_ms = info.start_time_ms;
		_a_end_time_ms = info.end_time_ms;
		_audio_info.push_back(info);
		_audio_decoder.add(info);
	}
	else {
		_v_start_time_ms = info.start_time_ms;
		_v_end_time_ms = info.end_time_ms;
		_video_info.push_back(info);
		_video_decoder.add(info);
	}

	if (_cur_a_ts_ms == INT64_MAX) {
		_cur_a_ts_ms = info.start_time_ms;
		_cur_v_ts_ms = info.start_time_ms;
	}

	if (_end_time_ms < info.end_time_ms) {
		_end_time_ms = info.end_time_ms;
	}
	
	av_log(NULL, AV_LOG_INFO, "CAVDecoder add info:%lf, %lf, %"PRIu64", %.3f\n", _cur_a_ts_ms, _cur_v_ts_ms, _end_time_ms, info.duration);

	return 0;
}

unsigned int CAVDecoder::getuid()
{
	return _uid;
}

extern double g_vframe_duration;


bool CAVDecoder::get_one_v_frame()
{
	int64_t ts;
	int ret = -1;
	if (_video_info.size()) {
		AVFrame * pFrame = NULL;
		ret = _video_decoder.get_one_frame(&pFrame, ts);
		if (ret == 0) {
			if (pFrame){
				free_cur_v_frame();
				_cur_v_frame = pFrame;
			}
			_cur_v_ts_ms += g_vframe_duration;
		}
		else {
			_video_info.pop_front();
			if (_cur_v_ts_ms < _end_time_ms) {
				_cur_v_ts_ms += g_vframe_duration;//return last v frame
				ret = 0;
			}
		}
	}

	if (ret) {//no video decoded
		if (_cur_v_ts_ms < _end_time_ms) {//should have as video frame
			_cur_v_ts_ms += g_vframe_duration;//return last v frame
			ret = 0;
    	}
	}

	return ret == 0;
}

std::string CAVDecoder::get_cur_vfile()
{
	if (_video_info.size()){
		return _video_info.front().name;
	}
	else {
		return "";
	}
}

std::string CAVDecoder::get_cur_afile()
{
	if (_audio_info.size()){
		return _audio_info.front().name;
	}
	else {
		return "";
	}
}

void CAVDecoder::free_cur_a_frame()
{
	if (_cur_a_frame) {
		av_frame_free(&_cur_a_frame);
	}
}

int CAVDecoder::scale_frame(AVFrame * pFrame, AVFrame * pScaledFrame, int scaled_width, int scaled_height)
{
	if (pFrame->width == _src_width && pFrame->height == _src_height && scaled_width == _scaled_width && scaled_height == _scaled_height) {
		return sws_scale(_sws_ctx, pFrame->data, pFrame->linesize, 0, pFrame->height,
			pScaledFrame->data, pScaledFrame->linesize);
	}
	else {
		if (_sws_ctx) {
			sws_freeContext(_sws_ctx);
			_sws_ctx = NULL;
		}
		_sws_ctx = sws_getContext(pFrame->width, pFrame->height, AV_PIX_FMT_YUV420P,
			scaled_width, scaled_height, AV_PIX_FMT_YUV420P, SWS_BILINEAR,
			NULL, NULL, NULL);
		if (!_sws_ctx) {
			return -1;
		}
		_src_width = pFrame->width;
		_src_height = pFrame->height;
		_scaled_width = scaled_width;
		_scaled_height = scaled_height;
		return sws_scale(_sws_ctx, pFrame->data, pFrame->linesize, 0, pFrame->height,
			pScaledFrame->data, pScaledFrame->linesize);
	}
}

void CAVDecoder::free_cur_v_frame()
{
	if (_cur_v_frame) {
		av_frame_free(&_cur_v_frame);
	}
}

bool CAVDecoder::get_one_a_frame()
{
	int64_t ts;
	int ret = -1;
	free_cur_a_frame();
	if (_audio_info.size()) {
		ret = _audio_decoder.get_one_frame(&_cur_a_frame, ts);
		if (ret == 0) {
			_cur_a_ts_ms += AFRAME_DURATION_MS;
		}
		else {
			_audio_info.pop_front();
			if (_cur_a_ts_ms < _end_time_ms) {
				_cur_a_ts_ms += AFRAME_DURATION_MS;//return silence frame
				ret = 0;
			}
		}
	}

	if (ret) {//no video decoded
		if (_cur_a_ts_ms < _end_time_ms) {//should have a audio frame
			_cur_a_ts_ms += AFRAME_DURATION_MS;//return last a frame
			ret = 0;
		}
	}

	return ret == 0;
}