|
From: Lasse Kärkkäi. <tr...@us...> - 2012-07-08 07:23:14
|
Author: Lasse Karkkainen <tro...@tr...>
Date: Sun Jul 8 10:19:22 2012 +0300
Cleanup of duplicated code in class FFmpeg. Changes to timecode calculation should not affect behavior.
---
game/ffmpeg.cc | 114 ++++++++++++++++++++++++--------------------------------
game/ffmpeg.hh | 7 +--
2 files changed, 52 insertions(+), 69 deletions(-)
diff --git a/game/ffmpeg.cc b/game/ffmpeg.cc
index 4578e08..fae6e3d 100644
--- a/game/ffmpeg.cc
+++ b/game/ffmpeg.cc
@@ -126,84 +126,68 @@ void FFmpeg::seek_internal() {
m_seekTarget = getNaN(); // Signal that seeking is done
}
-struct ReadFramePacket: public AVPacket {
- AVFormatContext* m_s;
- ReadFramePacket(AVFormatContext* s): m_s(s) {
- if (av_read_frame(s, this) < 0) throw FFmpeg::eof_error();
- }
- ~ReadFramePacket() { av_free_packet(this); }
-};
-
void FFmpeg::decodePacket() {
+ struct ReadFramePacket: public AVPacket {
+ AVFormatContext* m_s;
+ ReadFramePacket(AVFormatContext* s): m_s(s) {
+ if (av_read_frame(s, this) < 0) throw FFmpeg::eof_error();
+ }
+ ~ReadFramePacket() { av_free_packet(this); }
+ };
+
+ struct AVFrameWrapper {
+ AVFrame* m_frame;
+ AVFrameWrapper(): m_frame(avcodec_alloc_frame()) {
+ if (!m_frame) throw std::runtime_error("Unable to allocate AVFrame");
+ }
+ ~AVFrameWrapper() { av_free(m_frame); }
+ operator AVFrame*() { return m_frame; }
+ AVFrame* operator->() { return m_frame; }
+ };
+
+ // Read an AVPacket and decode it into AVFrames
ReadFramePacket packet(m_formatContext);
int packetSize = packet.size;
while (packetSize) {
if (packetSize < 0) throw std::logic_error("negative packet size?!");
if (m_quit || m_seekTarget == m_seekTarget) return;
if (packet.stream_index != m_streamId) return;
- int decodeSize = 0;
- if (m_mediaType == AVMEDIA_TYPE_VIDEO) decodeSize = decodeVideoFrame(packet);
- if (m_mediaType == AVMEDIA_TYPE_AUDIO) decodeSize = decodeAudioFrame(packet);
+ AVFrameWrapper frame;
+ int frameFinished = 0;
+ int decodeSize = (m_mediaType == AVMEDIA_TYPE_VIDEO ? avcodec_decode_video2 : avcodec_decode_audio4)(m_codecContext, frame, &frameFinished, &packet);
+ if (decodeSize < 0) throw std::runtime_error("cannot decode avframe");
packetSize -= decodeSize; // Move forward within the packet
+ if (!frameFinished) continue;
+ // Update current position if timecode is available
+ if (frame->pkt_pts != uint64_t(AV_NOPTS_VALUE)) {
+ m_position = double(frame->pkt_pts) * av_q2d(m_formatContext->streams[m_streamId]->time_base);
+ }
+ if (m_mediaType == AVMEDIA_TYPE_VIDEO) processVideo(frame); else processAudio(frame);
}
}
-struct AVFrameWrapper {
- AVFrame* m_frame;
- AVFrameWrapper(): m_frame(avcodec_alloc_frame()) {
- if (!m_frame) throw std::runtime_error("Unable to allocate AVFrame");
- }
- ~AVFrameWrapper() { av_free(m_frame); }
- operator AVFrame*() { return m_frame; }
- AVFrame* operator->() { return m_frame; }
-};
-
-int FFmpeg::decodeVideoFrame(ReadFramePacket& packet) {
- struct AVFrameWrapper videoFrame;
-
- int frameFinished = 0;
- int decodeSize = avcodec_decode_video2(m_codecContext, videoFrame, &frameFinished, &packet);
- if (decodeSize < 0) throw std::runtime_error("cannot decode video frame");
- if (frameFinished) {
- // Convert into RGB and scale the data
- int w = (m_codecContext->width+15)&~15;
- int h = m_codecContext->height;
- std::vector<uint8_t> buffer(w * h * 3);
- {
- uint8_t* data = &buffer[0];
- int linesize = w * 3;
- sws_scale(m_swsContext, videoFrame->data, videoFrame->linesize, 0, h, &data, &linesize);
- }
- // Timecode calculation
- m_position = double(videoFrame->pkt_pts) * av_q2d(m_formatContext->streams[m_streamId]->time_base);
- // Construct a new video frame and push it to output queue
- VideoFrame* tmp = new VideoFrame(m_position, w, h);
- tmp->data.swap(buffer);
- videoQueue.push(tmp); // Takes ownership and may block
+void FFmpeg::processVideo(AVFrame* frame) {
+ // Convert into RGB and scale the data
+ int w = (m_codecContext->width+15)&~15;
+ int h = m_codecContext->height;
+ std::vector<uint8_t> buffer(w * h * 3);
+ {
+ uint8_t* data = &buffer[0];
+ int linesize = w * 3;
+ sws_scale(m_swsContext, frame->data, frame->linesize, 0, h, &data, &linesize);
}
- return decodeSize;
+ // Construct a new video frame and push it to output queue
+ VideoFrame* tmp = new VideoFrame(m_position, w, h);
+ tmp->data.swap(buffer);
+ videoQueue.push(tmp); // Takes ownership and may block
}
-int FFmpeg::decodeAudioFrame(ReadFramePacket& packet) {
- struct AVFrameWrapper audioFrame;
-
- int gotFrame = 0;
- int decodeSize = avcodec_decode_audio4(m_codecContext, audioFrame, &gotFrame, &packet);
- if (decodeSize < 0) throw std::runtime_error("cannot decode audio frame");
- if (gotFrame) {
- std::vector<int16_t> resampled(AVCODEC_MAX_AUDIO_FRAME_SIZE);
- // Use number of samples from AVFrame
- int frames = audio_resample(m_resampleContext, &resampled[0], (short*)audioFrame->data[0], audioFrame->nb_samples);
- resampled.resize(frames * AUDIO_CHANNELS);
- // Use timecode from packet if available
- if (uint64_t(packet.pts) != uint64_t(AV_NOPTS_VALUE)) {
- m_position = double(packet.pts) * av_q2d(m_formatContext->streams[m_streamId]->time_base);
- }
- // Push to output queue (may block)
- audioQueue.push(resampled, m_position);
- // Increment current time
- m_position += double(resampled.size())/double(audioQueue.getSamplesPerSecond());
- }
- return decodeSize;
+void FFmpeg::processAudio(AVFrame* frame) {
+ // Resample to output sample rate, then push to audio queue and increment timecode
+ std::vector<int16_t> resampled(AVCODEC_MAX_AUDIO_FRAME_SIZE);
+ int frames = audio_resample(m_resampleContext, &resampled[0], (short*)frame->data[0], frame->nb_samples);
+ resampled.resize(frames * AUDIO_CHANNELS);
+ audioQueue.push(resampled, m_position); // May block
+ m_position += double(frames)/m_formatContext->streams[m_streamId]->codec->sample_rate;
}
diff --git a/game/ffmpeg.hh b/game/ffmpeg.hh
index 4d4619a..c7578ee 100644
--- a/game/ffmpeg.hh
+++ b/game/ffmpeg.hh
@@ -198,12 +198,11 @@ extern "C" {
struct AVCodec;
struct AVCodecContext;
struct AVFormatContext;
+ struct AVFrame;
struct ReSampleContext;
struct SwsContext;
}
-struct ReadFramePacket;
-
/// ffmpeg class
class FFmpeg {
public:
@@ -230,8 +229,8 @@ class FFmpeg {
void seek_internal();
void open();
void decodePacket();
- int decodeVideoFrame(ReadFramePacket& packet);
- int decodeAudioFrame(ReadFramePacket& packet);
+ void processVideo(AVFrame* frame);
+ void processAudio(AVFrame* frame);
std::string m_filename;
unsigned int m_rate;
volatile bool m_quit;
|