Transcoder - hereforu/tizen-multimedia-apps GitHub Wiki

##Multimedia Native App ๋งŒ๋“ค๊ธฐ - 1. Transcoder**

  1. Transcoder Application ๊ฐœ์š”
  2. ํ™”๋ฉด ๊ตฌ์„ฑ
  3. Media Demuxer, Media Codec, Media Muxer ํ™œ์šฉ
  4. Transcoding

Transcoder Application ๊ฐœ์š”

Transcoder Application์€ ๋‹จ๋ง์— ์ €์žฅ๋˜์–ด ์žˆ๋Š” ๋™์˜์ƒ ์ค‘ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•˜๋ฉด

  • video codec
  • video resolution
  • audio codec

์„ ๋ณ€๊ฒฝํ•˜์—ฌ ์ƒˆ๋กœ์šด ๋™์˜์ƒ์„ ์ƒ์„ฑํ•˜์—ฌ ํŒŒ์ผ๋กœ ์ €์žฅํ•˜๋Š” Application์ด๋‹ค.

๊ฐœ๋ฐœ์ž๋Š” Transcoder Application์„ ํ†ตํ•ด Tizen 3.0์— ์ƒˆ๋กญ๊ฒŒ ์ถ”๊ฐ€๋œ Media Demuxer์™€ Media Muxer ์‚ฌ์šฉ๋ฒ•๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, Tizen 2.4 feature ์ธ Media Codec, Media Transformer์˜ ํ™œ์šฉ ์˜ˆ๋„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ™”๋ฉด ๊ตฌ์„ฑ

  • VideoListView: Transcoding ๋Œ€์ƒ ํŒŒ์ผ ์„ ํƒ ํ™”๋ฉด

VideoListView.h VideoListView.cpp

  • InfoView: ์„ ํƒํ•œ Video ํŒŒ์ผ ์ƒ์„ธ ์ •๋ณด ์ œ๊ณต ํ™”๋ฉด

InfoView.h InfoView.cpp

  • OptionView:Transcoding Option ์„ ํƒ ํ™”๋ฉด

OptionView.h OptionView.cpp

transcoder views

Media Demuxer, Media Codec, Media Muxer ํ™œ์šฉ

  • Demuxer ๊ตฌํ˜„

demuxer.h demuxer.cpp

class Demuxer { public: Demuxer(); ~Demuxer(); void Create(const char* srcfilename); void Destroy(); void Start(); bool ReadSeample(int track_index, media_packet_h* packet); bool IsEoS(int track_index); void Stop(); unsigned int GetNumTracks(); media_format_h GetMediaFormat(int track_index); bool GetVideoDecInfo(CodecInfo& vdec); bool GetAudioDecInfo(CodecInfo& adec); int GetVideoTrackIndex(); int GetAudioTrackIndex(); private: ... };


>* `Demuxer::Create`์—์„œ๋Š” `mediademuxer_create`๋ฅผ ํ†ตํ•ด demuxer๋ฅผ ์ƒ์„ฑํ•˜๊ณ , EoS(End of Stream)์™€ Error Event๋ฅผ ๋ฐ›๊ธฐ ์œ„ํ•œ Callback ํ•จ์ˆ˜๋ฅผ `mediademuxer_set_eos_cb`์™€ `mediademuxer_set_error_cb`๋กœ ๊ฐ๊ฐ ๋“ฑ๋กํ•œ๋‹ค. ์œ„ ๊ณผ์ •์ด ์„ฑ๊ณตํ•˜๋ฉด demuxingํ•  file์„ `mediademuxer_set_data_source`๋ฅผ ํ†ตํ•ด ์„ค์ •ํ•˜๊ณ  `mediademuxer_prepare` ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด demuxer ์ƒํƒœ๋ฅผ MEDIADEMUXER_STATE_IDLE์—์„œ MEDIADEMUXER_STATE_READY๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค.

> ```{.c++}
void Demuxer::Create(const char* srcfilename)
{
	int ret = MEDIADEMUXER_ERROR_NONE;
	if((ret = mediademuxer_create(&m_demuxer)) != MEDIADEMUXER_ERROR_NONE)
		throw_error_and_destroy_demuxer(m_demuxer, "fail to create demuxer: ", ret);
	if((ret = mediademuxer_set_eos_cb(m_demuxer, demuxer_eos_cb, (void*)this)) != MEDIADEMUXER_ERROR_NONE)
		throw_error_and_destroy_demuxer(m_demuxer, "fail to mediademuxer_set_eos_cb: ", ret);
	if((ret = mediademuxer_set_error_cb(m_demuxer, demuxer_error_cb, (void*)this)) != MEDIADEMUXER_ERROR_NONE)
		throw_error_and_destroy_demuxer(m_demuxer, "fail to mediademuxer_set_error_cb: ", ret);
	if((ret = mediademuxer_set_data_source(m_demuxer, srcfilename)) != MEDIADEMUXER_ERROR_NONE)
		throw_error_and_destroy_demuxer(m_demuxer, "fail to mediademuxer_set_data_source: ", ret);
	if((ret = mediademuxer_prepare(m_demuxer)) != MEDIADEMUXER_ERROR_NONE)
		throw_error_and_destroy_demuxer(m_demuxer, "fail to mediademuxer_prepare: ", ret);	
}

์ฐธ๊ณ ๋กœ throw_error_and_destroy_demuxer๋Š” ํ•จ์ˆ˜ ์‹คํ–‰ ๊ฒฐ๊ณผ๊ฐ€ MEDIADEMUXER_ERROR_NONE ์ด ์•„๋‹ˆ๋ฉด runtime error๋ฅผ throw ํ•˜๊ณ  demuxer ๊ฐ์ฒด๋ฅผ destroyํ•˜๋Š” macro์ด๋‹ค.

#define throw_error_and_destroy_demuxer(demuxer, msg, error_code)
{
if(demuxer)
{
mediademuxer_destroy(demuxer);
demuxer = NULL;
}
throw std::runtime_error(std::string(msg)+AppTool::ToString(error_code));
}\



>* demuxer๊ฐ€ _MEDIADEMUXER_STATE_READY_ ์ƒํƒœ๊ฐ€ ๋˜๋ฉด, ์„ค์ •ํ•œ media file์— ๋“ค์–ด์žˆ๋Š” track๋“ค์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค. `mediademuxer_get_track_count`๋ฅผ ํ†ตํ•ด์„œ track ๊ฐœ์ˆ˜๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๊ณ , `mediademuxer_get_track_info`๋ฅผ ํ†ตํ•ด์„œ ๊ฐ track์˜ media_format_h๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค. ํš๋“ํ•œ medai_format_h๋Š” ๋ฐ˜๋“œ์‹œ `media_format_unref`๋ฅผ ํ†ตํ•ด์„œ reference count๋ฅผ ์ค„์—ฌ์ค˜์•ผ ํ•œ๋‹ค.

> ```{.c++}
void Demuxer::ExtractTrackinfo()
{
	int trackcount = 0;
	iferror_throw(mediademuxer_get_track_count(m_demuxer, &trackcount), "fail to mediademuxer_get_track_count: ");
	for(int i= 0; i < trackcount; ++i)
	{
		TrackForDemuxer track;
		iferror_throw(mediademuxer_get_track_info(m_demuxer, i, &track.info.fmt), "fail to mediademuxer_get_track_info: ");
		media_format_type_e formattype;
		int ret = MEDIA_FORMAT_ERROR_NONE;
		if((ret = media_format_get_type(track.info.fmt, &formattype))== MEDIA_FORMAT_ERROR_NONE)
		{
			switch(formattype)
			{
				case MEDIA_FORMAT_VIDEO:
					m_videotrackindex = i;
					m_tracks.push_back(track);
					break;
				case MEDIA_FORMAT_AUDIO:
					m_audiotrackindex = i;
					m_tracks.push_back(track);
					break;
				default:
					dlog_print(DLOG_ERROR, "Demuxer", "unsupportive type (%d)", (int)formattype);
					break;
			}
		}
		else
		{
			dlog_print(DLOG_ERROR, "Demuxer", "fail to media_format_get_type (%d)", ret);
		}
	}
}
  • Track์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์–ป์—ˆ๋‹ค๋ฉด demuxing์„ ํ†ตํ•ด ์–ป๊ณ ์ž ํ•˜๋Š” sample์˜ track์„ ์„ ํƒํ•˜๊ณ  mediademuxer_start๋ฅผ ํ†ตํ•ด MEDIADEMUXER_STATE_RUNNING ์ƒํƒœ๋กœ ๋งŒ๋“ค์–ด์ค€๋‹ค.

void Demuxer::Start() { //in this sample code, we support only one video track and one audio track! if(m_videotrackindex != -1) iferror_throw(mediademuxer_select_track(m_demuxer, m_videotrackindex), "fail to mediademuxer_select_track for video: "); if(m_audiotrackindex != -1) iferror_throw(mediademuxer_select_track(m_demuxer, m_audiotrackindex), "fail to mediademuxer_select_track for audio: "); iferror_throw(mediademuxer_start(m_demuxer), "fail to mediademuxer_start: "); }


>* _MEDIADEMUXER_STATE_RUNNING_ ์ƒํƒœ์—์„œ๋Š” ์„ ํƒํ•œ track์„ ๊ตฌ์„ฑํ•˜๋Š” packet๋“ค์„ `mediademuxer_read_sample`๋ฅผ ํ†ตํ•ด ์ˆœ์ฐจ์ ์œผ๋กœ ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค. ์ด๋•Œ ์ฃผ์˜ํ•  ์ ์€ ๋งˆ์ง€๋ง‰ packet์— EOS flag๊ฐ€ ์„ค์ •๋˜์–ด ์žˆ์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ์ฐธ๊ณ ๋กœ EOS callback์€ ๋งˆ์ง€๋ง‰ packet์„ ์ฝ๊ณ ๋‚˜๋ฉด ๋ฐœ์ƒํ•œ๋‹ค. ๋งˆ์ง€๋ง‰ packet์— EOS flag๋ฅผ ์„ค์ •ํ•˜๊ณ ์ž ํ•œ๋‹ค๋ฉด `media_packet_set_flags`๋ฅผ ํ†ตํ•ด์„œ ์„ค์ • ๊ฐ€๋Šฅํ•˜๋‹ค. 

> ```{.c++}
int Demuxer::read_sample(int track_index, media_packet_h* packet)
{
   *packet = NULL;
   return mediademuxer_read_sample(m_demuxer, track_index, packet);        
}
  • demuxing์„ ์ค‘์ง€ํ•˜๊ณ ์ž ํ•˜๋ฉด mediademuxer_stop์„ ํ˜ธ์ถœํ•˜์—ฌ ๋‹ค์‹œ MEDIADEMUXER_STATE_READY ์ƒํƒœ๋กœ ๋งŒ๋“ค์–ด ์ฃผ๋ฉด ๋œ๋‹ค. ์„ ํƒํ–ˆ๋˜ track ์€ mediademuxer_unselect_track๋ฅผ ํ†ตํ•ด์„œ ๋‹ค์‹œ ์„ ํƒํ•ด์ œ ํ•œ๋‹ค. unselect๋ฅผ ํ•˜์ง€ ์•Š๊ฒŒ ๋˜๋ฉด mediamuxer_unprepare๋ฅผ ์‹คํŒจํ•˜๊ฒŒ ๋œ๋‹ค.

void Demuxer::Stop() { iferror_throw(mediademuxer_stop(m_demuxer), "fail to mediademuxer_stop: "); if(m_videotrackindex != -1) iferror_throw(mediademuxer_unselect_track(m_demuxer, m_videotrackindex), "fail to mediademuxer_unselect_track for video: "); if(m_audiotrackindex != -1) iferror_throw(mediademuxer_unselect_track(m_demuxer, m_audiotrackindex), "fail to mediademuxer_unselect_track for audio: "); }


>* demuxer  ์‚ฌ์šฉ์ด ์™„๋ฃŒ๋˜๋ฉด unprepare, destroy๊ณผ์ •์„ ํ†ตํ•ด ์‚ฌ์šฉํ–ˆ๋˜ ๋ชจ๋“  ์ž์›์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
> ```{.c++}
void Demuxer::Destroy()
{
	if(m_demuxer == NULL)
		return;
	for(int i= 0; i < m_tracks.size(); ++i)
	{
		if(m_tracks[i].info.fmt)
			media_format_unref(m_tracks[i].info.fmt);
	}
	m_tracks.clear();
	mediademuxer_unset_eos_cb(m_demuxer);
	mediademuxer_unset_error_cb(m_demuxer);
	//if ready state
	mediademuxer_unprepare(m_demuxer);
	mediademuxer_destroy(m_demuxer);
	m_demuxer = NULL;
}
  • Muxer ๊ตฌํ˜„

muxer.h muxer.cpp

class Muxer { public: Muxer(); ~Muxer(); void Create(const char* dstfilepath, mediamuxer_output_format_e format); void Destroy(); int AddTrack(media_format_h media_format); void CloseTrack(int track_index); void Start(); bool WriteSample(int track_index, media_packet_h sample); void Stop(); private: mediamuxer_h m_muxer; std::string m_dstfilename; };


>* Muxer๋˜ํ•œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•œ๋‹ค. `Muxer::Create`์—์„œ๋Š” `mediamuxer_create`๋ฅผ ํ†ตํ•ด muxer๋ฅผ ์ƒ์„ฑํ•˜๊ณ , muxing ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•  format๊ณผ ํŒŒ์ผ ์ด๋ฆ„์„ `mediamuxer_set_data_sink`๋กœ ์„ค์ •ํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ ์ฃผ์˜ํ•  ์ ์€ ํŒŒ์ผ ์ด๋ฆ„์„ local memory์— ๋„ฃ์–ด์„œ ๋„˜๊ฒจ์ฃผ๋ฉด ์•ˆ๋œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. Platform์—์„œ ๋ณ„๋„ memory๋ฅผ ํ• ๋‹นํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์˜ค๋™์ž‘์ด ์ผ์–ด๋‚˜๊ฒŒ ๋œ๋‹ค. Tizen3.0์—์„œ ์ง€์›ํ•˜๋Š” format์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

> ```{.c++}
typedef enum {
	MEDIAMUXER_CONTAINER_FORMAT_MP4 = MEDIA_FORMAT_CONTAINER_MP4,	/**< The mediamuxer output format is MP4 container */
	MEDIAMUXER_CONTAINER_FORMAT_3GP = MEDIA_FORMAT_CONTAINER_3GP,	/**< The mediamuxer output format is 3GP container */
	MEDIAMUXER_CONTAINER_FORMAT_WAV = MEDIA_FORMAT_CONTAINER_WAV,	/**< The mediamuxer output format is WAV container */
	MEDIAMUXER_CONTAINER_FORMAT_AMR_NB = MEDIA_FORMAT_AMR_NB,	/**< The mediamuxer output format is ARM_NB container */
	MEDIAMUXER_CONTAINER_FORMAT_AMR_WB = MEDIA_FORMAT_AMR_WB,	/**< The mediamuxer output format is AMR_WB container */
	MEDIAMUXER_CONTAINER_FORMAT_AAC_ADTS = MEDIA_FORMAT_CONTAINER_AAC_ADTS	/**< The mediamuxer output format is AAC_ADTS container */
} mediamuxer_output_format_e;

void Muxer::Create(const char* dstfilepath, mediamuxer_output_format_e format) { m_dstfilename = dstfilepath; iferror_throw(mediamuxer_create(&m_muxer), "fail to mediamuxer_create"); int ret = MEDIAMUXER_ERROR_NONE; if((ret = mediamuxer_set_data_sink(m_muxer, const_cast<char*>(m_dstfilename.c_str()), format))!= MEDIAMUXER_ERROR_NONE) { mediamuxer_destroy(m_muxer); m_muxer = NULL; throw std::runtime_error("fail to mediamuxer_set_data_sinkr"); } }


>* Muxer ์ƒ์„ฑ์— ์„ฑ๊ณตํ•˜๋ฉด `mediamuxer_add_track`์„ ํ†ตํ•ด video/audio track์„ ์ถ”๊ฐ€ํ•˜๊ณ  track์˜ format ์ •๋ณด๋ฅผ ์•Œ๋ ค์ค˜์•ผ ํ•œ๋‹ค. format ์ •๋ณด๋Š” `media_format`ํ•จ์ˆ˜๋“ค์„ ํ†ตํ•ด์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. ๋ณธ sample app์—์„œ๋Š” video/audio encoder์—์„œ format์„ ์ƒ์„ฑํ•˜์—ฌ ์ œ๊ณตํ•œ๋‹ค.   

> ```{.c++}
//note that you should add error handling codes for each media_format function calls
media_format_h video_fmt;
int ret = media_format_create(&video_fmt);
ret = media_format_set_video_mime(video_fmt, MEDIA_FORMAT_H264_SP);	
ret = media_format_set_video_width(video_fmt, 640);
ret = media_format_set_video_height(video_fmt, 480);
ret = media_format_set_video_avg_bps(video_fmt, 256000);
ret = media_format_set_video_max_bps(video_fmt, 256000);

int Muxer::AddTrack(media_format_h media_format) { int index = -1; iferror_throw(mediamuxer_add_track(m_muxer, media_format, &index), "fail to mediamuxer_add_track"); return index; }


>* track์ด ์„ฑ๊ณต์ ์œผ๋กœ ์ถ”๊ฐ€๋˜์—ˆ๋‹ค๋ฉด muxing์„ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค. `mediamuxer_prepare`๋กœ _MEDIA_MUXER_READY_STATE_ ๋กœ ๋งŒ๋“ค๊ณ  ๋ฐ”๋กœ `mediamuxer_start`๋กœ _RUNNING_ ์ƒํƒœ๋ฅผ ๋งŒ๋“ค์ž. Media Demuxer์™€ ๋‹ค๋ฅด๊ฒŒ Muxer์—์„œ๋Š” _MEDIA_MUXER_READY_STATE_ ์—์„œ ํ•  ์ˆ˜ ์žˆ๋Š” ์ž‘์—…์ด start์™ธ์—๋Š” ์—†๋‹ค. `mediamuxer_prepare`์„ฑ๊ณตํ–ˆ๋‹ค๋ฉด ๋ฐ”๋กœ `mediamuxer_start`๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๋˜๊ฒ ๋‹ค.

> ```{.c++}
void Muxer::Start()
{
	iferror_throw(mediamuxer_prepare(m_muxer), "fail to mediamuxer_prepare");
	int ret = MEDIAMUXER_ERROR_NONE;
	if((ret = mediamuxer_start(m_muxer))!= MEDIAMUXER_ERROR_NONE)
	{
		mediamuxer_unprepare(m_muxer);
		m_muxer = NULL;
		throw std::runtime_error("fail to mediamuxer_start");
	}
}
  • MEDIA_MUXER_RUNNING_STATE ์—์„  packet์„ writeํ•  ์ˆ˜ ์žˆ๋‹ค. Muxer๋Š” video/audio encoding์„ ํ•˜์ง€ ์•Š๊ณ  container format์— ๋งž์ถฐ์–ด multiplexing๋งŒ ์ˆ˜ํ–‰ํ•œ๋‹ค. Media Codec์„ ์‚ฌ์šฉํ•ด์„œ encoding ๋œ packet ์„ ๋„ฃ์–ด์ฃผ๋ฉด ๋œ๋‹ค.

bool Muxer::WriteSample(int track_index, media_packet_h sample) { int ret = MEDIAMUXER_ERROR_NONE; if((ret = mediamuxer_write_sample(m_muxer, track_index, sample))!= MEDIAMUXER_ERROR_NONE) { dlog_print(DLOG_ERROR, "Muxer", "fail to mediamuxer_write_sample:%d", ret); return false; } return true; }


>* packet write ๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด ์ƒ์„ฑ ์ˆœ์„œ์™€ ์—ญ์ˆœ์œผ๋กœ resource๋ฅผ ์ •๋ฆฌํ•ด์•ผ ํ•œ๋‹ค. `mediamuxer_stop`-> `mediamuxer_unprepare` -> `mediamuxer_destroy`


* Codec ๊ตฌํ˜„

> [codecbase.h](https://github.com/hereforu/tizen-multimedia-apps/blob/master/transcoder/inc/codecbase.h)
> [codecbase.cpp](https://github.com/hereforu/tizen-multimedia-apps/blob/master/transcoder/src/codecbase.cpp)

> [videodecoder.h](https://github.com/hereforu/tizen-multimedia-apps/blob/master/transcoder/inc/videodecoder.h)
> [videodecoder.cpp](https://github.com/hereforu/tizen-multimedia-apps/blob/master/transcoder/src/videodecoder.cpp)

> [videoencoder.h](https://github.com/hereforu/tizen-multimedia-apps/blob/master/transcoder/inc/videoencoder.h)
> [videoencoder.cpp](https://github.com/hereforu/tizen-multimedia-apps/blob/master/transcoder/src/videoencoder.cpp)

> [audiodecoder.h](https://github.com/hereforu/tizen-multimedia-apps/blob/master/transcoder/inc/audiodecoder.h)
> [audiodecoder.cpp](https://github.com/hereforu/tizen-multimedia-apps/blob/master/transcoder/src/audiodecoder.cpp)

> [audioencoder.h](https://github.com/hereforu/tizen-multimedia-apps/blob/master/transcoder/inc/audioencoder.h)
> [audioencoder.cpp](https://github.com/hereforu/tizen-multimedia-apps/blob/master/transcoder/src/audioencoder.cpp)

>* Codec์€ [tizen media codec](https://developer.tizen.org/development/api-references/native-application?redirect=/dev-guide/2.3.1/org.tizen.native.mobile.apireference/group__CAPI__MEDIA__CODEC__MODULE.html)์„ ํ™œ์šฉํ•˜์—ฌ ๊ตฌํ˜„๋˜์—ˆ์œผ๋ฉฐ ์•„๋ž˜ ๊ทธ๋ฆผ๊ณผ ๊ฐ™์ด CodecBase๋ฅผ base class๋กœ ํ•˜์—ฌ video/audio encoder/decoder๋ฅผ ๋งŒ๋“œ๋Š” ๊ตฌ์กฐ๋กœ ๊ตฌํ˜„ํ•˜์˜€๋‹ค.

> ![codec structure](https://github.com/hereforu/tizen-multimedia-apps/blob/master/Wiki_Images/codec_structure.png)

> ```{.c++}
class CodecBase
{
public:
	CodecBase();
	virtual ~CodecBase();
	void Create(const CodecInfo& codecinfo);
	void Destroy();
	bool GetPacket(media_packet_h& packet);
	bool InsertPacket(media_packet_h packet);
	bool IsEoS();
        ...
};
  • Codec์€ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ธฐ๋ณธ ์ •๋ณด๋ฅผ ์„ค์ •ํ•˜๋Š” ๊ฒƒ๋ถ€ํ„ฐ Demuxer/Muxer ๋ณด๋‹ค ๋ณต์žกํ•˜๋‹ค.
  1. ์ผ๋‹จ mediacodec_create๋กœ codec์„ ์ƒ์„ฑํ•˜๊ณ  handle์„ ๋„˜๊ฒจ ๋ฐ›๋Š”๋‹ค.
  1. mediacodec_set_codec์œผ๋กœ codec์„ ์„ค์ •ํ•œ๋‹ค. Tizen code ์— ์˜ํ•˜๋ฉด ์„ค์ • ๊ฐ€๋Šฅํ•œ codec ์€ ์—ฌ๊ธฐ์„œ ํ™•์ธํ•˜์ž.
  1. ์„ค์ •ํ•œ codec์— ๋งž๋Š” ์„ธ๋ถ€์ •๋ณด๋ฅผ ์„ค์ •ํ•œ๋‹ค. audio decoder๋ผ๋ฉด mediacodec_set_adec_info๋ฅผ ์‚ฌ์šฉํ•ด ์„ธ๋ถ€ ์ •๋ณด๋ฅผ ์„ค์ •ํ•˜๊ณ , audio encder๋Š” mediacodec_set_aenc_info, video decoder๋Š” mediacodec_set_vdec_info, video encoder๋Š” mediacodec_set_venc_info๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.
  1. ํ•„์š”ํ•œ callback ํ•จ์ˆ˜๋“ค์„ ์„ค์ •ํ•œ๋‹ค. mediacodec_set_eos_cb์™€ mediacodec_set_error_cb๋Š” ๊ฐ๊ฐ eos์™€ error ์•Œ๋ฆผ์„ ๋ฐ›๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค. mediacodec_set_input_buffer_used_cb๋Š” input์œผ๋กœ ๋„ฃ์–ด์ค€ packet์˜ ์‚ฌ์šฉ์ด ์™„๋ฃŒ๋˜๋ฉด ํ˜ธ์ถœ๋˜๋Š” callback์„ ์„ค์ •ํ•˜๋Š” ํ•จ์ˆ˜์ด๋‹ค. ํšจ์œจ์ ์ธ memory ์‚ฌ์šฉ์„ ์œ„ํ•ด ์—ฌ๊ธฐ์„œ ์‚ฌ์šฉ ์™„๋ฃŒ๋œ packet์„ destroyํ•œ๋‹ค. encoding/decoding๋œ ๊ฒฐ๊ณผ๋Š” mediacodec_set_output_buffer_available_cb๋ฅผ ํ†ตํ•ด ์„ค์ •ํ•œ callbackํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๋„˜์–ด์˜จ๋‹ค. ์ฃผ์˜ํ•  ์ ์€ callback ํ•จ์ˆ˜์˜ parameter๋กœ ๋„˜์–ด์˜จ packet์ด ๊ฒฐ๊ณผ packet์ด ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์ด๋‹ค. callback์ด ํ˜ธ์ถœ๋œ ์‹œ์ ์— mediacodec_get_output์„ ํ†ตํ•ด ์–ป์–ด์™€์•ผ ํ•œ๋‹ค. ์™œ ์ด๋ ‡๊ฒŒ ๋˜์–ด ์žˆ๋Š”์ง€๋Š” ์•„์ง ๋‚ด๊ณต์ด ๋ถ€์กฑํ•ด์„œ...
  1. prepare๊นŒ์ง€ ํ•˜๋ฉด packet์„ ์ง‘์–ด ๋„ฃ์–ด encoding/decodingํ•  ์ค€๋น„๊ฐ€ ์™„๋ฃŒ๋œ๋‹ค.

//callback functions declaration static void mc_input_buffer_used_cb(media_packet_h pkt, void *user_data); static void mc_output_buffer_available_cb(media_packet_h pkt, void *user_data); static void mc_error_cb(mediacodec_error_e error, void *user_data); static void mc_eos_cb(void *user_data);


> ```{.c++}
typedef struct _VDecInfo
{
	mediacodec_codec_type_e codecid;
	int width;
	int height;
}VDecInfo;
typedef struct _VEncInfo
{
	mediacodec_codec_type_e codecid;
	int width;
	int height;
	int fps;
	int target_bits;
}VEncInfo;
typedef struct _ADecInfo
{
	mediacodec_codec_type_e codecid;
	int samplerate;
	int channel;
	int bit;
}ADecInfo;
typedef struct _AEncInfo
{
	mediacodec_codec_type_e codecid;
	int samplerate;
	int channel;
	int bit;
	int bitrate;
}AEncInfo;
typedef union _CodecInfo
{
	VDecInfo vdec;
	VEncInfo venc;
	ADecInfo adec;
	AEncInfo aenc;
}CodecInfo;
void CodecBase::Create(const CodecInfo& codecinfo)
{
	iferror_throw(mediacodec_create(&m_mediacodec), "fail to create mediacodec_create");
	if(create(m_mediacodec, codecinfo) == false)//this function should be defined in each derived class
		throw_error_and_destroy_codec(m_mediacodec, "fail to create specific codec", 0)
	int ret = MEDIACODEC_ERROR_NONE;
	if((ret = mediacodec_set_eos_cb(m_mediacodec, mc_eos_cb, (void*)this)) != MEDIACODEC_ERROR_NONE)
		throw_error_and_destroy_codec(m_mediacodec, "fail to mediacodec_set_eos_cb", ret);
	if((ret = mediacodec_set_error_cb(m_mediacodec, mc_error_cb, (void*)this)) != MEDIACODEC_ERROR_NONE)
		throw_error_and_destroy_codec(m_mediacodec, "fail to mediacodec_set_error_cb", ret);
	if((ret = mediacodec_set_input_buffer_used_cb(m_mediacodec, mc_input_buffer_used_cb, (void*)this)) != MEDIACODEC_ERROR_NONE)
		throw_error_and_destroy_codec(m_mediacodec, "fail to mediacodec_set_input_buffer_used_cb", ret);
	if((ret = mediacodec_set_output_buffer_available_cb(m_mediacodec, mc_output_buffer_available_cb, (void*)this)) != MEDIACODEC_ERROR_NONE)
		throw_error_and_destroy_codec(m_mediacodec, "fail to mediacodec_set_output_buffer_available_cb", ret);
	if((ret = mediacodec_prepare(m_mediacodec)) != MEDIACODEC_ERROR_NONE)
		throw_error_and_destroy_codec(m_mediacodec, "fail to mediacodec_prepare", ret);
}

//an example of specific codec creation bool VideoDecoder::create(mediacodec_h mediacodec, const CodecInfo& codecinfo) { int ret = MEDIACODEC_ERROR_NONE; if((ret = mediacodec_set_codec(mediacodec, codecinfo.vdec.codecid, MEDIACODEC_DECODER|MEDIACODEC_SUPPORT_TYPE_SW)) != MEDIACODEC_ERROR_NONE) { dlog_print(DLOG_ERROR, "CodecBase", "fail to mediacodec_set_codec [%d]", ret); return false; } if((ret = mediacodec_set_vdec_info(mediacodec, codecinfo.vdec.width, codecinfo.vdec.height)) != MEDIACODEC_ERROR_NONE) { dlog_print(DLOG_ERROR, "CodecBase", "fail to mediacodec_set_vdec_info [%d]", ret); return false; } return true; }


>* encoding/decodingํ•  packet์„ ์ˆœ์„œ๋Œ€๋กœ ๋ฐ€์–ด ๋„ฃ๋Š”๋‹ค.

> ```{.c++}
bool CodecBase::InsertPacket(media_packet_h packet)
{
	int ret = mediacodec_process_input(m_mediacodec, packet, 1000);
	if(ret != MEDIACODEC_ERROR_NONE)
	{
		dlog_print(DLOG_ERROR, "CodecBase", "fail to mediacodec_process_input %d [%s]", ret, getname());
		return false;
	}
	return true;
}
  • ์ด์   eos ๋˜๋Š” error๊ฐ€ ๋ฐœ์ƒํ•  ๋•Œ๊นŒ์ง€ ์ƒ์„ฑ์‹œ ์„ค์ •ํ•œ mc_input_buffer_used_cb, mc_output_buffer_available_cb callback ํ•จ์ˆ˜๋ฅผ handling ํ•˜๋ฉด ๋œ๋‹ค.

์ „์ˆ ํ•œ ๋ฐ”์™€ ๊ฐ™์ด mc_input_buffer_used_cb๋Š” input์œผ๋กœ ๋„ฃ์–ด์ค€ packet์ด codec ๊ฐ์ฒด์—์„œ ๋”์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์œผ๋ฉด ํ˜ธ์ถœ๋œ๋‹ค. callback์ด ํ˜ธ์ถœ๋˜๋ฉด packet์„ destroy ํ•œ๋‹ค.

void CodecBase::handle_input_buffer_used(media_packet_h pkt) { media_packet_destroy(pkt); } //callback function void CodecBase::mc_input_buffer_used_cb(media_packet_h pkt, void user_data) { CodecBase codec = (CodecBase*)user_data; codec->handle_input_buffer_used(pkt); }


>> `mc_output_buffer_available_cb`๋Š” ๊ฒฐ๊ณผ packet์ด ๋งŒ๋“ค์–ด์ง€๋ฉด ํ˜ธ์ถœ๋œ๋‹ค. packet์„ ํš๋“ฃํ•˜์—ฌ ์ ์ ˆํ•œ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋ฉด ๋œ๋‹ค. ๋ณธ sample code์—์„œ๋Š” output queue๋ฅผ ๋‘์–ด queue์— ๊ฒฐ๊ณผ ํŒŒ์ผ์„ insertํ•œ๋‹ค. 

>> ```{.c++}
void CodecBase::handle_output_buffer_available(media_packet_h pkt)
{
	media_packet_h output_buf = NULL;
	int ret = mediacodec_get_output(m_mediacodec, &output_buf, 0);
	if(ret != MEDIACODEC_ERROR_NONE)
	{
		dlog_print(DLOG_ERROR, "CodecBase", "fail to mediacodec_get_output %d [%s]", ret, getname());
	}
	pushpacket_to_outputqueue(output_buf);
}
//callback function
void CodecBase::mc_output_buffer_available_cb(media_packet_h pkt, void *user_data)
{
	CodecBase* codec = (CodecBase*)user_data;
	codec->handle_output_buffer_available(pkt);
}
  • encoding/decoding์ด ์™„๋ฃŒ๋˜๋ฉด mediacodec_unprepare ํ•˜๊ณ  mediacodec_destroy๋ฅผ ํ˜ธ์ถœํ•ด์„œ ์ž์›์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

Transcoding

transcodingengine.h transcodingengine.cpp

class TranscodingEngine { public: enum { DEMUX_COUNTER = 0, DECODE_COUNTER, ENCODE_COUNTER, MAX_COUNTER }; enum { VIDEO_DECODER = 0, VIDEO_ENCODER, AUDIO_DECODER, AUDIO_ENCODER, MAX_CODEC, }; TranscodingEngine(); ~TranscodingEngine(); void Destroy(); void Transcoding(const char* srcfilename, unsigned int duration, const CodecInfo& venc, const CodecInfo& aenc); void Cancel(); double GetProgress(); const char* GetDstFileName(); bool IsCanceled(); private: ... private: Demuxer* m_demuxer; Muxer* m_muxer; ImageResizer* m_resizer; CodecBase* m_codec[MAX_CODEC]; ... };


>* TranscodingEngine class๋Š” ์ง€๊ธˆ๊นŒ์ง€ ์„ค๋ช…ํ•œ demuxer, muxer, codec, ๊ทธ๋ฆฌ๊ณ  image transform ๊ธฐ๋Šฅ์„ ๋ชจ๋‘ ์‚ฌ์šฉํ•˜์ง€๋งŒ ์™ธ๋ถ€์— Transcoding๊ณผ Cancel๋งŒ ์ œ๊ณตํ•œ๋‹ค.
>* Transcoding์„ ์‹œ์ž‘ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” transcodingํ•  ํŒŒ์ผ ์ด๋ฆ„ `srcfilename`๊ณผ video/audio encoder ์ •๋ณด์ธ `CodecInfo venc/aenc`๋ฅผ ์„ค์ •ํ•ด์•ผ ํ•œ๋‹ค. video/audio encoder ์ •๋ณด๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.
> ```{.c++}
typedef struct _VEncInfo
{
	mediacodec_codec_type_e codecid;
	int width;
	int height;
	int fps;
	int target_bits;
}VEncInfo;
typedef struct _AEncInfo
{
	mediacodec_codec_type_e codecid;
	int samplerate;
	int channel;
	int bit;
	int bitrate;
}AEncInfo;
  • Transcoding ํ•จ์ˆ˜์—์„œ๋Š” ์œ„ ์ •๋ณด๋“ค์„ ๋ฐ›์•„ demuxer, muxer, codec, image_resizer ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. ์ด ์ค‘ ํ•˜๋‚˜๋ผ๋„ ์‹คํŒจํ•˜๋ฉด run-time exception์„ ๋ฐœ์ƒ์‹œํ‚ค์–ด Transcoding์„ ์ข…๋ฃŒํ•œ๋‹ค. Transcoding ํ•จ์ˆ˜์—์„œ๋Š” prepareํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํ•„์š” ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

void TranscodingEngine::prepare(const char* srcfilename, unsigned int duration, const CodecInfo& venc, const CodecInfo& aenc) { m_dstfilename = generatedstfilename(srcfilename); create_demuxer(srcfilename); CodecInfo option[MAX_CODEC]; option[VIDEO_ENCODER] = venc; option[AUDIO_ENCODER] = aenc; fill_and_get_codec_info(option[VIDEO_DECODER], option[AUDIO_DECODER], option[VIDEO_ENCODER], option[AUDIO_ENCODER]); for(int i = 0; i < MAX_CODEC; ++i) create_codec(i, option[i]); create_muxer(srcfilename); if(option[VIDEO_ENCODER].venc.width != option[VIDEO_DECODER].vdec.width || option[VIDEO_ENCODER].venc.height != option[VIDEO_DECODER].vdec.height) create_resizer(option[VIDEO_ENCODER].venc.width, option[VIDEO_ENCODER].venc.height); }


>>* `generatedstfilename` ํ•จ์ˆ˜๋Š” source ํŒŒ์ผ ์ด๋ฆ„์˜ ๋งˆ์ง€๋ง‰์— _trans๋ฅผ ๋ถ™์—ฌ source ํŒŒ์ผ๊ณผ ๊ฐ™์€ ํด๋”์— ๊ฒฐ๊ณผ ํŒŒ์ผ์ด ๋งŒ๋“ค์–ด์งˆ ์ˆ˜ ์žˆ๋„๋ก ์ƒ์„ฑํ•œ๋‹ค. ๋งŒ์ผ ๋™์ผ ํŒŒ์ผ์ด ์ด๋ฏธ ์กด์žฌํ•˜๋ฉด _trans๋’ค๋กœ ์ผ๋ จ ๋ฒˆํ˜ธ๋ฅผ ๋ถ™์ด๋„๋ก ์ž‘์„ฑํ•˜์˜€๋‹ค.
>>* `create_demuxer`๋Š” ์ด๋ฏธ ์„ค๋ช…ํ•œ demuxer ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋ฉค๋ฒ„ ๋ณ€์ˆ˜์— ํ• ๋‹นํ•˜๋Š” ํ•จ์ˆ˜์ด๋‹ค. ์ƒ์„ฑ ์ค‘๊ฐ„์— exception์ด ๋ฐœ์ƒํ•ด๋„ memory leak์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก auto_ptr๋กœ ์ƒ์„ฑํ•œ๋‹ค. exception์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์œผ๋ฉด auto_ptr์„ ํ•ด์ œํ•˜๊ณ  ์ƒ์„ฑ๋œ ๊ฐ์ฒด๋ฅผ member ๋ณ€์ˆ˜์— ํ• ๋‹นํ•˜์—ฌ ์ƒ์„ฑ์„ ์™„๋ฃŒํ•œ๋‹ค. 

>> ```{.c++}
void TranscodingEngine::create_demuxer(const char* srcfilename)
{
	std::auto_ptr<Demuxer> demuxer(new Demuxer);
	demuxer->Create(srcfilename);
	demuxer->ExtractTrackinfo();
	m_demuxer = demuxer.release();
}
  • create_muxer, create_resizer, create_codec ๋ชจ๋‘ ์ด์™€ ๊ฐ™์€ ๋ฐฉ๋ฒ•์œผ๋กœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ํ™œ์šฉ ์ „ ๋‹จ๊ณ„๊นŒ์ง€ ์ดˆ๊ธฐํ™”ํ•˜์—ฌ ์ค€๋น„ํ•œ๋‹ค.

void TranscodingEngine::create_codec(int codectype, const CodecInfo& codecinfo) { CodecBase* p = NULL; switch(codectype) { case VIDEO_DECODER: p = (CodecBase*)new VideoDecoder; break; case VIDEO_ENCODER: p = (CodecBase*)new VideoEncoder; break; case AUDIO_DECODER: p = (CodecBase*)new AudioDecoder; break; case AUDIO_ENCODER: p = (CodecBase*)new AudioEncoder; break; default: throw std::runtime_error("invalid codec type"); break; } std::auto_ptr codec(p); codec->Create(codecinfo); m_codec[codectype] = codec.release(); }


>> ```{.c++}
void TranscodingEngine::create_muxer(const char* srcfilename)
{
	std::auto_ptr<Muxer> muxer(new Muxer);
	muxer->Create(generatedstfilename(srcfilename), MEDIAMUXER_CONTAINER_FORMAT_MP4);
	m_muxer_video_track_index = muxer->AddTrack(m_codec[VIDEO_ENCODER]->GetMediaFormat());
	m_muxer_audio_track_index = muxer->AddTrack(m_codec[AUDIO_ENCODER]->GetMediaFormat());
	m_muxer = muxer.release();
}

void TranscodingEngine::create_resizer(int target_width, int target_height) { std::auto_ptr resizer(new ImageResizer); resizer->Create(target_width, target_height); m_resizer = resizer.release(); }


>* ํ•„์š” ๊ฐ์ฒด ์ค€๋น„๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด demuxer์™€ muxer๋ฅผ start ์‹œํ‚ค๊ณ  transcoding์„ ์ง„ํ–‰ํ•œ๋‹ค. ๋ชจ๋“  packet์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๊ฐ€ ๋๋‚˜๋ฉด muxer์™€ demuxer๋ฅผ stopํ•˜๊ณ  transcoding์„ ์™„๋ฃŒํ•œ๋‹ค.

> ```{.c++}
void TranscodingEngine::Transcoding(const char* srcfilename, unsigned int duration, const CodecInfo& venc, const CodecInfo& aenc)
{
	device_power_request_lock(POWER_LOCK_CPU, 0);
	prepare(srcfilename, duration, venc, aenc);
	m_demuxer->Start();
	m_muxer->Start();
	transcoding();
	m_muxer->Stop();
	m_demuxer->Stop();
	unprepare();
	device_power_release_lock(POWER_LOCK_CPU);
}
  • transcoding ํ•จ์ˆ˜๋Š” ๊ฐ track์— ๋Œ€ํ•ด์„œ packet ๊ฐ๊ฐ์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๋ฅผ PTS(Presentaion Time Stamp)๋ฅผ ๊ณ ๋ คํ•˜์—ฌ ์ง„ํ–‰ํ•œ๋‹ค. PTS๋ฅผ ๊ณ ๋ คํ•˜์ง€ ์•Š๊ณ  ์ง„ํ–‰ํ•˜๋ฉด demuxer ๋‚ด๋ถ€์—์„œ buffering ๋œ packet์ด ๋งŽ์•„์ ธ ์†๋„๊ฐ€ ๋А๋ ค์ง€๊ฑฐ๋‚˜ hang์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ฃผ์˜ํ•œ๋‹ค. ๋˜ํ•œ ๋งค iteration๋งˆ๋‹ค sleep์„ ๋„ฃ์–ด ์ฃผ์–ด demuxer, muxer, codec ์ด ์›ํ• ํžˆ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค€๋‹ค.

void TranscodingEngine::transcoding() { int video_counter[MAX_COUNTER] = {0,}; //to represent the progress int audio_counter[MAX_COUNTER] = {0,}; int iteration = 0; unsigned int video_pts = 0, audio_pts = 0; m_bcanceled = false; while(!m_bcanceled) { process_track(m_demuxer->GetVideoTrackIndex(), m_muxer_video_track_index, m_codec[VIDEO_DECODER], m_codec[VIDEO_ENCODER], video_counter, video_pts); do { process_track(m_demuxer->GetAudioTrackIndex(), m_muxer_audio_track_index, m_codec[AUDIO_DECODER], m_codec[AUDIO_ENCODER], audio_counter, audio_pts); }while(audio_pts <= video_pts && m_codec[AUDIO_ENCODER]->IsEoS()==false); if(m_codec[VIDEO_ENCODER]->IsEoS() == true && m_codec[AUDIO_ENCODER]->IsEoS() == true) { break; } m_progress_count = video_counter[ENCODE_COUNTER]; usleep(500000); } m_muxer->CloseTrack(m_muxer_video_track_index); m_muxer->CloseTrack(m_muxer_audio_track_index); usleep(1000000); }


>>* ๊ฐ track์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์ง„ํ–‰๋œ๋‹ค.

>>>* `feed_decoder_with_packet`: demuxer๋กœ๋ถ€ํ„ฐ encoded packet์„ ์ฝ์–ด์™€ decoder์˜ input queue์— ๋„ฃ์–ด์ค€๋‹ค.

>>> ```{.c++}
bool TranscodingEngine::feed_decoder_with_packet(CodecBase* decoder, int track_index, int& count, unsigned int& pts)
{
	media_packet_h demux_packet = NULL;
	if(m_demuxer->IsEoS(track_index) == true)
		return true;
	if(m_demuxer->ReadSeample(track_index, &demux_packet))
	{
		++count;
		pts = get_pts_in_msec(demux_packet);
		dlog_print(DLOG_DEBUG, "TranscodingEngine", "%dth demuxed packet [pts:%u]", count, pts);
		if(!decoder->InsertPacket(demux_packet))
		{
			dlog_print(DLOG_ERROR, "TranscodingEngine", "while putting the %d th packet to the decoder", count);
			return false;
		}
	}
	return true;
}
  • feed_encoder_with_packet: decoder๋กœ๋ถ€ํ„ฐ decoding๋œ packet์„ ์ฝ์–ด์™€ encoder์˜ input queue์— ๋„ฃ์–ด์ค€๋‹ค. image์˜ ๊ฒฝ์šฐ ํ•„์š”ํ•˜๋‹ค๋ฉด image transform์„ ํ™œ์šฉํ•˜์—ฌ resizing ํ•ด์ค€๋‹ค.

bool TranscodingEngine::feed_encoder_with_packet(CodecBase* decoder, CodecBase* encoder, int& count) { media_packet_h decoded_packet = NULL; if(decoder->IsEoS()==true) return true; if(decoder->GetPacket(decoded_packet)) { ++count; dlog_print(DLOG_DEBUG, "TranscodingEngine", "%dth decoded packet", count); if(m_resizer) //there will be no resizer object if the resolutions of a source and a target video are identical { if(resize_resolution_if_image(&decoded_packet)==false) { dlog_print(DLOG_ERROR, "TranscodingEngine", "while resizing the %d th packet", count); return false; } } if(encoder->InsertPacket(decoded_packet)==false) { dlog_print(DLOG_ERROR, "TranscodingEngine", "while putting the %d th packet to the encoder", count); return false; } } return true; }


>>>* `feed_muxer_with_packet`: encoder๋กœ๋ถ€ํ„ฐ encoding๋œ packet์„ ์ฝ์–ด์™€ muxer๋ฅผ ํ†ตํ•ด writeํ•œ๋‹ค. 

>>> ```{.c++}
bool TranscodingEngine::feed_muxer_with_packet(CodecBase* encoder, int muxer_track_index, int& count)
{
	bool bret = true;
	if(encoder == NULL)
		return false;
	media_packet_h encoded_packet;
	if(encoder->IsEoS()==false)
	{
		if(encoder->GetPacket(encoded_packet))
		{
			++count;
			bret = m_muxer->WriteSample(muxer_track_index, encoded_packet);
			media_packet_destroy(encoded_packet);
			dlog_print(DLOG_DEBUG, "TranscodingEngine", "%dth encoded packet", count);
		}
	}
	return bret;
}
  • ์œ„ ๊ณผ์ •์ค‘ ํ•˜๋‚˜๋ผ๋„ ์‹คํŒจํ•˜๋ฉด process_track์€ exception์„ ๋ฐœ์ƒ์‹œํ‚ค๊ณ  transcoding์„ ์ข…๋ฃŒํ•œ๋‹ค.

void TranscodingEngine::process_track(int track_index, int muxer_track_index, CodecBase* decoder, CodecBase* encoder, int counter[], unsigned int& pts) { if(encoder->IsEoS()==true) return; if(feed_decoder_with_packet(decoder, track_index, counter[DEMUX_COUNTER], pts)==false) { throw std::runtime_error("fail to feed_decoder_with_packet"); } if(feed_encoder_with_packet(decoder, encoder, counter[DECODE_COUNTER])==false) { throw std::runtime_error("fail to feed_encoder_with_packet"); } if(feed_muxer_with_packet(encoder, muxer_track_index, counter[ENCODE_COUNTER])==false) { throw std::runtime_error("fail to feed_muxer_with_packet"); } }

โš ๏ธ **GitHub.com Fallback** โš ๏ธ