// // C++ Implementation: k9avidecode // // Description: // // // Author: Jean-Michel PETIT , (C) 2007 // // Copyright: See COPYING file that comes with this distribution // // #include "config.h" #include "k9avidecode.h" // This is probably the incorrect revision for when CODEC_TYPE_VIDEO was removed // Please update the comparison below if you know the exact revision that CODEC_TYPE_VIDEO was removed in! #if LIBAVCODEC_VERSION_INT < (AV_VERSION_INT(52,72,2)) #define AVMEDIA_TYPE_VIDEO CODEC_TYPE_VIDEO #endif #if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(51,42,0) #define AV_PIX_FMT_RGB24 PIX_FMT_RGB24 #endif #include #include #include #include #include "ac.h" static int sws_flags = SWS_BICUBIC; k9AviDecode::k9AviDecode(TQObject *parent, const char *name) : TQObject(parent, name) { #if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58,9,100) av_register_all(); #endif m_opened=false; m_FormatCtx = NULL; m_CodecCtx = NULL; m_Codec = NULL; m_Frame = NULL; m_FrameRGB = NULL; m_buffer = NULL; } k9AviDecode::~k9AviDecode() { if (m_opened) close(); } #include "k9avidecode.moc" bool k9AviDecode::open(const TQString & _fileName) { m_error=""; if (m_opened) close(); // Open video file #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 2, 0) if (avformat_open_input(&m_FormatCtx, _fileName.utf8(), NULL, NULL)!=0) #else if (av_open_input_file(&m_FormatCtx, _fileName.utf8(), NULL, 0, NULL)!=0) #endif { m_error=i18n("Couldn't open the file %1").arg(_fileName); return false; // Couldn't open file} } // Retrieve stream information #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 6, 0) if (avformat_find_stream_info(m_FormatCtx, NULL)<0) #else if (av_find_stream_info(m_FormatCtx)<0) #endif { m_error =i18n("Couldn't find stream information"); return false; // Couldn't find stream information } unsigned int i; // Find the first video stream m_videoStream=-1; for (i=0; inb_streams; i++) #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 33, 100) if (m_FormatCtx->streams[i]->codecpar->codec_type==AVMEDIA_TYPE_VIDEO) #else if (m_FormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO) #endif { m_videoStream=i; break; } if (m_videoStream==-1) { m_error=i18n("The file doesn't contain any video stream"); return false; // Didn't find a video stream } // Find the decoder for the video stream #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 33, 100) m_Codec=(AVCodec *)avcodec_find_decoder(m_FormatCtx->streams[m_videoStream]->codecpar->codec_id); #else m_Codec=(AVCodec *)avcodec_find_decoder(m_FormatCtx->streams[m_videoStream]->codec->codec_id); #endif if (m_Codec==NULL) { m_error=i18n("Unsupported codec"); return false; // Codec not found } // Get/allocate a pointer to the codec context for the video stream #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 33, 100) m_CodecCtx = avcodec_alloc_context3(m_Codec); if (m_CodecCtx) { avcodec_parameters_to_context(m_CodecCtx, m_FormatCtx->streams[m_videoStream]->codecpar); } else { m_error=i18n("Failed to allocate a codec context"); return false; } #else m_CodecCtx=m_FormatCtx->streams[m_videoStream]->codec; #endif // Open codec #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 8, 0) if (avcodec_open2(m_CodecCtx, m_Codec, NULL)<0) #else if (avcodec_open(m_CodecCtx, m_Codec)<0) #endif { m_error =i18n("Could'nt open the codec"); return false; // Could not open codec } // Allocate video frame #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 45, 101) m_Frame=av_frame_alloc(); #else m_Frame=avcodec_alloc_frame(); #endif // Allocate an AVFrame structure #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 45, 101) m_FrameRGB=av_frame_alloc(); #else m_FrameRGB=avcodec_alloc_frame(); #endif if (m_FrameRGB==NULL) { m_error =i18n ("Unable to allocate memory for frames"); return false; } int numBytes; // Determine required buffer size and allocate buffer #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 24, 100) numBytes=av_image_get_buffer_size(AV_PIX_FMT_RGB24, m_CodecCtx->width, m_CodecCtx->height, 1); #else numBytes=avpicture_get_size(AV_PIX_FMT_RGB24, m_CodecCtx->width, m_CodecCtx->height); #endif m_buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t)); // Assign appropriate parts of buffer to image planes in pFrameRGB // Note that pFrameRGB is an AVFrame, but AVFrame is a superset // of AVPicture #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 24, 100) av_image_fill_arrays(m_FrameRGB->data, m_FrameRGB->linesize, m_buffer, AV_PIX_FMT_RGB24, m_CodecCtx->width, m_CodecCtx->height, 1); #else avpicture_fill((AVPicture *)m_FrameRGB, m_buffer, AV_PIX_FMT_RGB24, m_CodecCtx->width, m_CodecCtx->height); #endif m_duration=(double)m_FormatCtx->duration / AV_TIME_BASE; m_opened=true; m_fileName=_fileName; return true; } void k9AviDecode::seek(double _seconds) { AVRational time_base = m_FormatCtx->streams[m_videoStream]->time_base; int64_t fspos = (int64_t)(_seconds * AV_TIME_BASE); fspos=av_rescale_q(fspos, AV_TIME_BASE_Q, time_base); int i=av_seek_frame(m_FormatCtx, m_videoStream, fspos, AVSEEK_FLAG_BACKWARD ); double pos=av_gettime() / 1000000; } void k9AviDecode::readFrame(double _seconds) { AVRational time_base = m_FormatCtx->streams[m_videoStream]->time_base; int64_t fspos = (int64_t)(_seconds * AV_TIME_BASE); fspos=av_rescale_q(fspos, AV_TIME_BASE_Q, time_base); int res=av_seek_frame(m_FormatCtx, m_videoStream, fspos, AVSEEK_FLAG_BACKWARD ); avcodec_flush_buffers(m_CodecCtx); int frameFinished=0; AVPacket *packet; #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 12, 100) packet = av_packet_alloc(); #else AVPacket _packet; av_init_packet(&_packet); packet = &_packet; #endif struct SwsContext *toRGB_convert_ctx; bool bFound=false; while (av_read_frame(m_FormatCtx, packet)>=0 && !bFound) { // Is this a packet from the video stream? if (packet->stream_index==m_videoStream) { // Decode video frame #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 37, 100) int ret = avcodec_receive_frame(m_CodecCtx, m_Frame); if (ret == 0) frameFinished = 1; else if (ret == AVERROR(EAGAIN)) ret = 0; if (ret == 0) ret = avcodec_send_packet(m_CodecCtx, packet); #elif LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 23, 0) avcodec_decode_video2(m_CodecCtx, m_Frame, &frameFinished, packet); #else avcodec_decode_video(m_CodecCtx, m_Frame, &frameFinished, packet->data, packet->size); #endif // Did we get a video frame? if (frameFinished) { int64_t cur_dts=fspos; #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(54, 2, 0) cur_dts = packet->dts; #else if (m_FormatCtx->cur_st) cur_dts = m_FormatCtx->cur_st->cur_dts; #endif if (cur_dts >=fspos) { bFound=true; toRGB_convert_ctx=sws_getContext(m_CodecCtx->width, m_CodecCtx->height, m_CodecCtx->pix_fmt, m_CodecCtx->width, m_CodecCtx->height, AV_PIX_FMT_RGB24, sws_flags,NULL,NULL,NULL); sws_scale(toRGB_convert_ctx, m_Frame->data, m_Frame->linesize, 0, m_CodecCtx->height, m_FrameRGB->data,m_FrameRGB->linesize); // convert frame to QImage SaveFrame(m_FrameRGB, m_CodecCtx->width, m_CodecCtx->height); sws_freeContext(toRGB_convert_ctx); } } } #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 25, 100) // Unreference the packet from av_read_frame av_packet_unref(packet); #else // Free the packet from av_read_frame av_free_packet(packet); #endif } #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 12, 100) av_packet_free(&packet); #endif } void k9AviDecode::SaveFrame(AVFrame *pFrame, int width, int height) { TQImage pix; int len =(int) (3*width*height); char c[255]; // Write header sprintf(c,"P6\n%d %d\n255\n", width, height); char *s= (char*) malloc(len+strlen(c)); tc_memcpy(s,c,strlen(c)); tc_memcpy(s+strlen(c),pFrame->data[0], len); pix.loadFromData((uchar*)s,strlen(c)+len); free(s); emit drawFrame( &pix); } void k9AviDecode::close() { if (m_opened) { // Free the RGB image av_free(m_buffer); av_free(m_FrameRGB); // Free the YUV frame av_free(m_Frame); // Close the codec avcodec_close(m_CodecCtx); // Close the video file #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53, 17, 0) avformat_close_input(&m_FormatCtx); #else av_close_input_file(m_FormatCtx); #endif #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 63, 100) avcodec_free_context(&m_CodecCtx); #endif m_opened=false; } } double k9AviDecode::getDuration() const { return m_duration; } bool k9AviDecode::opened() const { return m_opened; } TQString k9AviDecode::getFileName() const { return m_fileName; } TQString k9AviDecode::getError() const { return m_error; }