@@ -1695,4 +1695,131 @@ FrameDims getHeightAndWidthFromOptionsOrAVFrame(
16951695 videoStreamOptions.width .value_or (avFrame.width ));
16961696}
16971697
1698+ Encoder::~Encoder () {
1699+ fclose (f_);
1700+ }
1701+
1702+ Encoder::Encoder (torch::Tensor& wf) : wf_(wf) {
1703+ f_ = fopen (" ./coutput" , " wb" );
1704+ TORCH_CHECK (f_, " Could not open file" );
1705+ const AVCodec* avCodec = avcodec_find_encoder (AV_CODEC_ID_MP3);
1706+ TORCH_CHECK (avCodec != nullptr , " Codec not found" );
1707+
1708+ AVCodecContext* avCodecContext = avcodec_alloc_context3 (avCodec);
1709+ TORCH_CHECK (avCodecContext != nullptr , " Couldn't allocate codec context." );
1710+ avCodecContext_.reset (avCodecContext);
1711+
1712+ avCodecContext_->bit_rate = 0 ; // TODO
1713+ avCodecContext_->sample_fmt = AV_SAMPLE_FMT_FLTP; // TODO
1714+ avCodecContext_->sample_rate = 16000 ; // TODO
1715+ AVChannelLayout channel_layout;
1716+ av_channel_layout_default (&channel_layout, 2 );
1717+ avCodecContext_->ch_layout = channel_layout;
1718+
1719+ auto ffmpegRet = avcodec_open2 (avCodecContext_.get (), avCodec, nullptr );
1720+ TORCH_CHECK (
1721+ ffmpegRet == AVSUCCESS, getFFMPEGErrorStringFromErrorCode (ffmpegRet));
1722+
1723+ AVFrame* avFrame = av_frame_alloc ();
1724+ TORCH_CHECK (avFrame != nullptr , " Couldn't allocate AVFrame." );
1725+ avFrame_.reset (avFrame);
1726+ avFrame_->nb_samples = avCodecContext_->frame_size ;
1727+ avFrame_->format = avCodecContext_->sample_fmt ;
1728+ avFrame_->sample_rate = avCodecContext_->sample_rate ;
1729+
1730+ ffmpegRet =
1731+ av_channel_layout_copy (&avFrame_->ch_layout , &avCodecContext_->ch_layout );
1732+ TORCH_CHECK (
1733+ ffmpegRet == AVSUCCESS,
1734+ " Couldn't copy channel layout to avFrame: " ,
1735+ getFFMPEGErrorStringFromErrorCode (ffmpegRet));
1736+ ffmpegRet = av_frame_get_buffer (avFrame_.get (), 0 );
1737+ TORCH_CHECK (
1738+ ffmpegRet == AVSUCCESS,
1739+ " Couldn't allocate avFrame's buffers: " ,
1740+ getFFMPEGErrorStringFromErrorCode (ffmpegRet));
1741+ }
1742+
1743+ torch::Tensor Encoder::encode () {
1744+ AVPacket* pkt = av_packet_alloc ();
1745+ if (!pkt) {
1746+ fprintf (stderr, " Could not allocate audio packet\n " );
1747+ exit (1 );
1748+ }
1749+
1750+ auto MAX_NUM_BYTES = 10000000 ; // 10Mb. TODO find a way not to pre-allocate.
1751+ int numEncodedBytes = 0 ;
1752+ torch::Tensor outputTensor = torch::empty ({MAX_NUM_BYTES}, torch::kUInt8 );
1753+ uint8_t * pOutputTensor =
1754+ static_cast <uint8_t *>(outputTensor.data_ptr <uint8_t >());
1755+
1756+ uint8_t * pWf = static_cast <uint8_t *>(wf_.data_ptr ());
1757+ auto numBytesWeWroteFromWF = 0 ;
1758+ auto numBytesPerSample = wf_.element_size ();
1759+ auto numBytesPerChannel = wf_.sizes ()[1 ] * numBytesPerSample;
1760+
1761+ // TODO need simpler/cleaner while loop condition.
1762+ while (numBytesWeWroteFromWF < numBytesPerChannel) {
1763+ auto ffmpegRet = av_frame_make_writable (avFrame_.get ());
1764+ TORCH_CHECK (
1765+ ffmpegRet == AVSUCCESS,
1766+ " Couldn't make AVFrame writable: " ,
1767+ getFFMPEGErrorStringFromErrorCode (ffmpegRet));
1768+
1769+ auto numBytesToWrite = numBytesPerSample * avCodecContext_->frame_size ;
1770+ if (numBytesWeWroteFromWF + numBytesToWrite > numBytesPerChannel) {
1771+ numBytesToWrite = numBytesPerChannel - numBytesWeWroteFromWF;
1772+ }
1773+ for (int ch = 0 ; ch < 2 ; ch++) {
1774+ memcpy (
1775+ avFrame_->data [ch], pWf + ch * numBytesPerChannel, numBytesToWrite);
1776+ }
1777+ pWf += numBytesToWrite;
1778+ numBytesWeWroteFromWF += numBytesToWrite;
1779+ encode_inner_loop (pkt, pOutputTensor, &numEncodedBytes, false );
1780+ }
1781+ encode_inner_loop (pkt, pOutputTensor, &numEncodedBytes, true );
1782+
1783+ return outputTensor.narrow (
1784+ /* dim=*/ 0 , /* start=*/ 0 , /* length=*/ numEncodedBytes);
1785+ // return outputTensor;
1786+ }
1787+
1788+ void Encoder::encode_inner_loop (
1789+ AVPacket* pkt,
1790+ uint8_t * pOutputTensor,
1791+ int * numEncodedBytes,
1792+ bool flush) {
1793+ int ffmpegRet = 0 ;
1794+
1795+ // TODO ewwww
1796+ if (flush) {
1797+ ffmpegRet = avcodec_send_frame (avCodecContext_.get (), nullptr );
1798+ } else {
1799+ ffmpegRet = avcodec_send_frame (avCodecContext_.get (), avFrame_.get ());
1800+ }
1801+ TORCH_CHECK (
1802+ ffmpegRet == AVSUCCESS,
1803+ " Error while sending frame: " ,
1804+ getFFMPEGErrorStringFromErrorCode (ffmpegRet));
1805+
1806+ while ((ffmpegRet = avcodec_receive_packet (avCodecContext_.get (), pkt)) >=
1807+ 0 ) {
1808+ if (ffmpegRet == AVERROR (EAGAIN) || ffmpegRet == AVERROR_EOF) {
1809+ return ;
1810+ }
1811+ TORCH_CHECK (
1812+ ffmpegRet >= 0 ,
1813+ " Error receiving packet: " ,
1814+ getFFMPEGErrorStringFromErrorCode (ffmpegRet));
1815+
1816+ fwrite (pkt->data , 1 , pkt->size , f_);
1817+
1818+ memcpy (pOutputTensor + *numEncodedBytes, pkt->data , pkt->size );
1819+ *numEncodedBytes += pkt->size ;
1820+
1821+ av_packet_unref (pkt);
1822+ }
1823+ }
1824+
16981825} // namespace facebook::torchcodec
0 commit comments