Advertisement
Guest User

converter.cpp

a guest
Jul 22nd, 2015
167
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 15.74 KB | None | 0 0
  1. #include "Converter.h"
  2. #include "InternetVideo.h"
  3.  
  4. Converter::Converter()
  5. {
  6.     av_register_all();
  7.     avcodec_register_all();
  8.  
  9.     m_Converting = false;
  10.  
  11.     connect(this, SIGNAL(ConvertingFinished(InternetVideo*)), this, SLOT(onConvertingFinished(InternetVideo*)));
  12.     m_FormatCtx = NULL;
  13.  
  14.     m_DecodedAudioFrame = nullptr;
  15.     m_DecodedVideoFrame = nullptr;
  16. }
  17.  
  18. void Converter::AddToQueue(InternetVideo* v)
  19. {
  20.     if (!v) return;
  21.     m_Queue.enqueue(v);
  22. }
  23.  
  24. void Converter::onConvertingFinished(InternetVideo *v)
  25. {
  26.     if (m_Queue.isEmpty())
  27.     {
  28.         emit QueueFinished();
  29.         return;
  30.     }
  31.  
  32.     Convert(m_Queue.dequeue());
  33. }
  34.  
  35. void Converter::StartConverting()
  36. {
  37.     if (m_Converting) return;
  38.  
  39.     m_Converting = true;
  40.     emit ConvertingFinished(nullptr);
  41. }
  42.  
  43. void Converter::Convert(InternetVideo *v)
  44. {
  45.     if (!v)
  46.     {
  47.         //TODO, output error message
  48.         emit ConvertingFinished(v);
  49.         return;
  50.     }
  51.  
  52.     QFile* file = v->GetDownloadedFile();
  53.     file->close(); //close file just in case
  54.  
  55.     //QFileInfo fileInfo(file->fileName());
  56.    
  57.  
  58.     QByteArray s = file->fileName().toUtf8();
  59.     char *path = s.data();
  60.  
  61.  
  62.     if (!OpenInput(path))
  63.         printf("ERROR"); //TODO
  64.  
  65.     QString targetFilename = v->GetTitle() + "." + m_FileEnding;
  66.     targetFilename = targetFilename.simplified();
  67.     targetFilename.replace(QRegExp("[" + QRegExp::escape("\\/:*?\"<>|") + "]"), QString("_"));
  68.  
  69.     if (!OpenOutput(targetFilename))
  70.         printf("ERROR");
  71.  
  72.     AVFrame* frame = avcodec_alloc_frame();
  73.     float audio_pts;
  74.     while (1)
  75.     {
  76.         AVPacket packet;
  77.         av_init_packet(&packet);
  78.         int rv = decode_frame(&packet, frame);
  79.         if (rv < 0)
  80.         {
  81.             break;
  82.         }
  83.         if (audio_st)
  84.             audio_pts = (double)audio_st->pts.val * audio_st->time_base.num / audio_st->time_base.den;
  85.         else
  86.             audio_pts = 0.0f;
  87.  
  88.         if (m_AudioCodecCtx)
  89.         {
  90.             if (got_frame)
  91.             {
  92.                 write_audio_frame(frame, audio_dst_data, audio_dst_bufsize);
  93.             }
  94.         }
  95.         if (audio_dst_data[0])
  96.         {
  97.             av_freep(&audio_dst_data[0]);
  98.             audio_dst_data[0] = NULL;
  99.         }
  100.  
  101.         av_free_packet(&packet);
  102.     }
  103.     write_delayed_frames(m_OutputFormatCtx, audio_st);
  104.     av_write_trailer(m_OutputFormatCtx);
  105.  
  106.     if (audio_st)
  107.         avcodec_close(audio_st->codec);
  108.     if (video_st)
  109.         avcodec_close(video_st->codec);
  110.  
  111.     avresample_close(m_avresampleCtx);
  112.     avcodec_free_frame(&frame);
  113.     emit ConvertingFinished(v);
  114. }
  115.  
  116. void Converter::SetFormatSettings(FileFormat format, int audioQuality, int videoQuality)
  117. {
  118.     m_Format = format;
  119.     m_audioOnly = true;
  120.     switch (m_Format)
  121.     {
  122.     case FileFormat::mp4:
  123.         m_VideoQuality = h264Qualities[videoQuality];
  124.         m_AudioQuality = mp3Qualities[audioQuality];
  125.         m_FileEnding = "mp4";
  126.         m_audioOnly = false;
  127.         break;
  128.     case FileFormat::mov:
  129.         m_VideoQuality = h264Qualities[videoQuality];
  130.         m_AudioQuality = mp3Qualities[audioQuality];
  131.         m_FileEnding = "mov";
  132.         m_audioOnly = false;
  133.         break;
  134.     case FileFormat::MP3:
  135.         m_AudioQuality = mp3Qualities[audioQuality];
  136.         m_FileEnding = "mp3";
  137.         break;
  138.     case FileFormat::FLAC:
  139.         m_VideoQuality = h264Qualities[videoQuality];
  140.         m_FileEnding = "flac";
  141.         break;
  142.     case FileFormat::WAV:
  143.         m_AudioQuality = losslessQualities[audioQuality];
  144.         m_FileEnding = "wav";
  145.         break;
  146.     }
  147. }
  148.  
  149. bool Converter::OpenInput(const char* path)
  150. {
  151.     /* open input file, and allocate format context */
  152.     if (avformat_open_input(&m_FormatCtx, path, NULL, NULL) < 0)
  153.     {
  154.         fprintf(stderr, "Could not open source file %s\n", path);
  155.         return false;
  156.     }
  157.  
  158.     // Retrieve stream information
  159.     if (avformat_find_stream_info(m_FormatCtx, NULL) < 0)
  160.         return false; // Couldn't find stream information
  161.  
  162.     // Dump information about file onto standard error
  163.     av_dump_format(m_FormatCtx, 0, path, 0);
  164.  
  165.     m_VideoStreamIndex = -1;
  166.     m_AudioStreamIndex = -1;
  167.    
  168.     // Find the first video stream
  169.     for (int i = 0; i < m_FormatCtx->nb_streams; i++)
  170.     {
  171.         if (m_FormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO && m_VideoStreamIndex == -1)
  172.         {
  173.             m_VideoStreamIndex = i;
  174.         }
  175.         if (m_FormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO && m_AudioStreamIndex == -1)
  176.         {
  177.             m_AudioStreamIndex = i;
  178.         }
  179.     }
  180.  
  181.     if (m_VideoStreamIndex == -1 || m_AudioStreamIndex == -1)
  182.         return false;
  183.  
  184.    
  185.     // Get a pointer to the codec context for the audio stream
  186.     m_VideoCodecCtx = m_FormatCtx->streams[m_VideoStreamIndex]->codec;
  187.     m_AudioCodecCtx = m_FormatCtx->streams[m_AudioStreamIndex]->codec;
  188.  
  189.     // Find the decoder for the video stream
  190.     m_VideoCodec = avcodec_find_decoder(m_VideoCodecCtx->codec_id);
  191.     if (m_VideoCodec == NULL) {
  192.         fprintf(stderr, "Unsupported video codec!\n");
  193.         return false; // Codec not found
  194.     }
  195.     // Find the decoder for the audio stream
  196.     m_AudioCodec = avcodec_find_decoder(m_AudioCodecCtx->codec_id);
  197.     if (m_AudioCodec == NULL) {
  198.         fprintf(stderr, "Unsupported audio codec!\n");
  199.         return false; // Codec not found
  200.     }
  201.  
  202.     // Open video codec
  203.     AVDictionary *codecDictOptions = NULL;
  204.     if (avcodec_open2(m_VideoCodecCtx, m_VideoCodec, &codecDictOptions) < 0)
  205.         return -1; // Could not open codec
  206.  
  207.     // Open audio codec
  208.     if (avcodec_open2(m_AudioCodecCtx, m_AudioCodec, &codecDictOptions) < 0)
  209.         return -1; // Could not open codec
  210.    
  211.     // Set up SWR context once you've got codec information
  212.     m_avresampleCtx = avresample_alloc_context();
  213.     av_opt_set_int(m_avresampleCtx, "in_channel_layout", m_AudioCodecCtx->channel_layout, 0);
  214.     av_opt_set_int(m_avresampleCtx, "out_channel_layout", av_get_default_channel_layout(m_AudioCodecCtx->channels), 0);
  215.     av_opt_set_int(m_avresampleCtx, "in_sample_rate", m_AudioCodecCtx->sample_rate, 0);
  216.     av_opt_set_int(m_avresampleCtx, "out_sample_rate", m_AudioQuality.samplingRate, 0);
  217.     av_opt_set_int(m_avresampleCtx, "in_sample_fmt", m_AudioCodecCtx->sample_fmt, 0);
  218.     av_opt_set_int(m_avresampleCtx, "out_sample_fmt", AV_SAMPLE_FMT_S16P, 0);
  219.  
  220.     AV_SAMPLE_FMT_FLTP
  221.     avresample_open(m_avresampleCtx);
  222.  
  223.     m_Audio_channels = m_AudioCodecCtx->channels;
  224.  
  225.     // Allocate audio frame
  226.     if (m_DecodedAudioFrame == NULL) m_DecodedAudioFrame = avcodec_alloc_frame();
  227.     int nb_planes = 0;
  228.     AVStream* audio_stream = m_FormatCtx->streams[m_AudioStreamIndex];
  229.     nb_planes = av_sample_fmt_is_planar(m_AudioCodecCtx->sample_fmt) ? m_AudioCodecCtx->channels : 1;
  230.     int tempSize = sizeof(uint8_t *) * nb_planes;
  231.     audio_dst_data = (uint8_t**)av_mallocz(tempSize);
  232.     if (!audio_dst_data)
  233.     {
  234.         fprintf(stderr, "Could not allocate audio data buffers\n");
  235.     }
  236.     else
  237.     {
  238.         for (int i = 0; i < nb_planes; i++)
  239.         {
  240.             audio_dst_data[i] = NULL;
  241.         }
  242.     }
  243.  
  244.     if (m_DecodedVideoFrame == NULL) m_DecodedVideoFrame = avcodec_alloc_frame();
  245.     // Determine required buffer size and allocate buffer
  246.     int numBytes = avpicture_get_size(PIX_FMT_RGB24, m_VideoCodecCtx->width, m_VideoCodecCtx->height);
  247.     video_dst_data = (uint8_t *)av_mallocz(numBytes*sizeof(uint8_t));
  248.  
  249.     return true;
  250. }
  251.  
  252. bool Converter::OpenOutput(QString targetFilename)
  253. {
  254.  
  255.     QByteArray fName = targetFilename.toLatin1();
  256.     const char* fileName = fName.data();
  257.  
  258.     QByteArray tPath = m_TargetPath.toLatin1();
  259.     const char* targetPath = tPath.data();
  260.  
  261.     QByteArray ext = m_FileEnding.toLatin1();
  262.    
  263.     /* allocate the output media context */
  264.     AVOutputFormat *opfmt = av_guess_format(ext.data(), fileName, NULL);
  265.  
  266.     switch (m_Format)
  267.     {
  268.     case FileFormat::MP3:
  269.     case FileFormat::FLAC:
  270.     case FileFormat::WAV:
  271.         opfmt->video_codec = AV_CODEC_ID_NONE;
  272.         break;
  273.     case FileFormat::mp4:
  274.     case FileFormat::mov:
  275.         opfmt->audio_codec = AV_CODEC_ID_MP3;
  276.         opfmt->video_codec = AV_CODEC_ID_H264;
  277.         break;
  278.     }
  279.  
  280.     AVStream *out_stream;
  281.     AVStream *in_stream;
  282.     AVCodecContext *dec_ctx, *enc_ctx;
  283.  
  284.     m_OutputFormatCtx = avformat_alloc_context();
  285.     if (!m_OutputFormatCtx) {
  286.         fprintf(stderr, "Memory error\n");
  287.         return false;
  288.     }
  289.  
  290.     sprintf(m_OutputFormatCtx->filename, "%s/%s", targetPath, fileName);
  291.     m_OutputFormatCtx->oformat = opfmt;
  292.  
  293.     // Add the audio stream using the default format codecs
  294.     // and initialize the codecs.
  295.     audio_st = NULL;
  296.     video_st = NULL;
  297.     if (opfmt->audio_codec != AV_CODEC_ID_NONE)
  298.     {
  299.         audio_st = add_audio_stream(m_OutputFormatCtx, &m_OutputAudioCodec, opfmt->audio_codec);
  300.     }
  301.     if (opfmt->video_codec != AV_CODEC_ID_NONE)
  302.     {
  303.         video_st = add_video_stream(m_OutputFormatCtx, &m_OutputVideoCodec, opfmt->video_codec);
  304.     }
  305.  
  306.     // Now that all the parameters are set, we can open the audio and
  307.     // video codecs and allocate the necessary encode buffers.
  308.     if (audio_st)
  309.     {
  310.         int rv = open_audio(m_OutputFormatCtx, m_OutputAudioCodec, audio_st);
  311.         if (rv < 0) return false;
  312.     }
  313.     if (video_st)
  314.     {
  315.         int rv = open_video(m_OutputFormatCtx, m_OutputVideoCodec, video_st);
  316.         if (rv < 0) return false;
  317.     }
  318.  
  319.     // open the output file, if needed
  320.     if (!(opfmt->flags & AVFMT_NOFILE))
  321.     {
  322.         if (avio_open(&m_OutputFormatCtx->pb, m_OutputFormatCtx->filename, AVIO_FLAG_WRITE) < 0) {
  323.             fprintf(stderr, "Could not open '%s'\n", m_OutputFormatCtx->filename);
  324.             return false;
  325.         }
  326.         // Write the stream header, if any.
  327.  
  328.         int res = avformat_write_header(m_OutputFormatCtx, NULL);
  329.         if (res < 0)
  330.         {
  331.             fprintf(stderr, "Error occurred when opening output file: %d\n", res);
  332.             return false;
  333.         }
  334.  
  335.     }
  336.  
  337.     return true;
  338. }
  339.  
  340. static const char *get_error_text(const int error)
  341. {
  342.     static char error_buffer[255];
  343.     av_strerror(error, error_buffer, sizeof(error_buffer));
  344.     return error_buffer;
  345. }
  346.  
  347. AVStream * Converter::add_audio_stream(AVFormatContext *oc, AVCodec **codec, enum AVCodecID codec_id)
  348. {
  349.     AVCodecContext *c;
  350.     AVStream *st;
  351.  
  352.     /* find the audio encoder */
  353.     *codec = avcodec_find_encoder(codec_id);
  354.     if (!(*codec)) {
  355.         fprintf(stderr, "Could not find codec\n");
  356.         return nullptr;
  357.     }
  358.  
  359.     st = avformat_new_stream(oc, *codec);
  360.     if (!st) {
  361.         fprintf(stderr, "Could not allocate stream\n");
  362.         return nullptr;
  363.     }
  364.  
  365.     //st->id = 0;
  366.  
  367.     c = st->codec;
  368.  
  369.     /* put sample parameters */
  370.     c->sample_fmt = AV_SAMPLE_FMT_S16P;
  371.     c->bit_rate = m_AudioQuality.bitrate;
  372.     c->sample_rate = m_AudioQuality.samplingRate;
  373.     c->channel_layout = av_get_default_channel_layout(m_AudioCodecCtx->channels);
  374.     c->channels = m_AudioCodecCtx->channels;
  375.    
  376.     // some formats want stream headers to be separate
  377.     if (oc->oformat->flags & AVFMT_GLOBALHEADER)
  378.         c->flags |= CODEC_FLAG_GLOBAL_HEADER;
  379.    
  380.     return st;
  381. }
  382.  
  383. AVStream * Converter::add_video_stream(AVFormatContext *oc, AVCodec **codec, enum AVCodecID codec_id)
  384. {
  385.     AVCodecContext *c;
  386.     AVStream *st;
  387.  
  388.     /* find the audio encoder */
  389.     *codec = avcodec_find_encoder(codec_id);
  390.     if (!(*codec)) {
  391.         fprintf(stderr, "Could not find codec\n");
  392.         return nullptr;
  393.     }
  394.  
  395.     st = avformat_new_stream(oc, *codec);
  396.     if (!st) {
  397.         fprintf(stderr, "Could not allocate stream\n");
  398.         return nullptr;
  399.     }
  400.  
  401.     c = st->codec;
  402.  
  403.     /* put sample parameters */
  404.     c->width = m_VideoCodecCtx->width;
  405.     c->height = m_VideoCodecCtx->height;
  406.     c->sample_aspect_ratio = m_VideoCodecCtx->sample_aspect_ratio;
  407.     c->pix_fmt = (*codec)->pix_fmts[0];
  408.     c->time_base = m_VideoCodecCtx->time_base;
  409.     c->bit_rate = m_VideoQuality.bitrate;
  410.     c->sample_rate = m_VideoQuality.bitrate;
  411.  
  412.     // some formats want stream headers to be separate
  413.     if (oc->oformat->flags & AVFMT_GLOBALHEADER)
  414.         c->flags |= CODEC_FLAG_GLOBAL_HEADER;
  415.  
  416.     return st;
  417. }
  418.  
  419. int Converter::open_audio(AVFormatContext *oc, AVCodec *codec, AVStream *st)
  420. {
  421.     int ret = 0;
  422.     AVCodecContext *c;
  423.  
  424.     st->duration = m_FormatCtx->duration;
  425.     c = st->codec;
  426.  
  427.     /* open it */
  428.     ret = avcodec_open2(c, codec, NULL);
  429.     if (ret < 0)
  430.     {
  431.         fprintf(stderr, "could not open codec\n");
  432.         return false;
  433.     }
  434.     if (c->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)
  435.         audio_input_frame_size = 10000;
  436.     else
  437.         audio_input_frame_size = c->frame_size;
  438.     int tempSize = audio_input_frame_size * av_get_bytes_per_sample(c->sample_fmt) * c->channels;
  439.     return ret;
  440.  
  441. }
  442.  
  443. int Converter::open_video(AVFormatContext *oc, AVCodec *codec, AVStream *st)
  444. {
  445.     int ret = 0;
  446.     AVCodecContext *c;
  447.  
  448.     st->duration = m_FormatCtx->duration;
  449.     c = st->codec;
  450.  
  451.     /* open it */
  452.     ret = avcodec_open2(c, codec, NULL);
  453.     if (ret < 0)
  454.     {
  455.         fprintf(stderr, "could not open codec\n");
  456.         return false;
  457.     }
  458.  
  459.     return ret;
  460. }
  461.  
  462. int Converter::decode_frame(AVPacket* packet, AVFrame* outputFrame)
  463. {
  464.     int rv = 0;
  465.     got_frame = 0;
  466.     if (m_FormatCtx == NULL)
  467.     {
  468.         return rv;
  469.     }
  470.  
  471.     int ret = 0;
  472.     audiobufsize = 0;
  473.     rv = av_read_frame(m_FormatCtx, packet);
  474.     if (rv < 0)
  475.     {
  476.         return rv;
  477.     }
  478.  
  479.     rv = decode_packet(packet, outputFrame);
  480.     return rv;
  481. }
  482.  
  483. int Converter::decode_packet(AVPacket* packet, AVFrame* outputFrame)
  484. {
  485.     int rv = 0;
  486.  
  487.     //audio stream?
  488.     if (packet->stream_index == m_AudioStreamIndex)
  489.     {
  490.         /* decode audio frame */
  491.         rv = avcodec_decode_audio4(m_AudioCodecCtx, m_DecodedAudioFrame, &got_frame, packet);
  492.         if (rv < 0)
  493.         {
  494.             fprintf(stderr, "Error decoding audio frame\n");
  495.             //return ret;
  496.         }
  497.         else
  498.         {
  499.             if (got_frame)
  500.             {
  501.                 if (audio_dst_data[0] == NULL)
  502.                 {
  503.                     rv = av_samples_alloc(audio_dst_data, &audio_dst_linesize, m_AudioCodecCtx->channels, m_DecodedAudioFrame->nb_samples, (AVSampleFormat)m_DecodedAudioFrame->format, 1);
  504.                     if (rv < 0)
  505.                     {
  506.                         fprintf(stderr, "Could not allocate audio buffer\n");
  507.                         return AVERROR(ENOMEM);
  508.                     }
  509.  
  510.                     /* TODO: extend return code of the av_samples_* functions so that this call is not needed */
  511.                     audio_dst_bufsize = av_samples_get_buffer_size(NULL, audio_st->codec->channels,
  512.                         m_DecodedAudioFrame->nb_samples, (AVSampleFormat)m_DecodedAudioFrame->format, 1);
  513.  
  514.                     //int16_t* outputBuffer = ...;
  515.                     avresample_convert(m_avresampleCtx, audio_dst_data, 0, outputFrame->nb_samples, m_DecodedAudioFrame->extended_data, 0, m_DecodedAudioFrame->nb_samples);
  516.                 }
  517.             }
  518.         }
  519.     }
  520.  
  521.     return rv;
  522. }
  523.  
  524. void Converter::write_audio_frame(AVFrame *frame, uint8_t ** audio_src_data, int audio_src_bufsize)
  525. {
  526.     AVFormatContext *oc = m_OutputFormatCtx;
  527.     AVStream *st = audio_st;
  528.     if (oc == NULL || st == NULL) return;
  529.     AVCodecContext *c;
  530.     AVPacket pkt = { 0 }; // data and size must be 0;
  531.     int got_packet;
  532.  
  533.     av_init_packet(&pkt);
  534.     c = st->codec;
  535.  
  536.     frame->nb_samples = audio_input_frame_size;
  537.     int buf_size = audio_src_bufsize * av_get_bytes_per_sample(c->sample_fmt) * c->channels;
  538.     avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt, *audio_src_data, buf_size, 1);
  539.     avcodec_encode_audio2(c, &pkt, frame, &got_packet);
  540.  
  541.     if (got_packet)
  542.     {
  543.         if (pkt.pts != AV_NOPTS_VALUE)
  544.             pkt.pts = av_rescale_q(pkt.pts, st->codec->time_base, st->time_base);
  545.         if (pkt.dts != AV_NOPTS_VALUE)
  546.             pkt.dts = av_rescale_q(pkt.dts, st->codec->time_base, st->time_base);
  547.         if (c && c->coded_frame && c->coded_frame->key_frame)
  548.             pkt.flags |= AV_PKT_FLAG_KEY;
  549.  
  550.         pkt.stream_index = st->index;
  551.         pkt.flags |= AV_PKT_FLAG_KEY;
  552.  
  553.         /* Write the compressed frame to the media file. */
  554.         if (av_interleaved_write_frame(oc, &pkt) != 0)
  555.         {
  556.             fprintf(stderr, "Error while writing audio frame\n");
  557.             return;
  558.         }
  559.     }
  560.  
  561.     av_free_packet(&pkt);
  562. }
  563.  
  564. void Converter::write_delayed_frames(AVFormatContext *oc, AVStream *st)
  565. {
  566.     AVCodecContext *c = st->codec;
  567.     int got_output = 0;
  568.     int ret = 0;
  569.     AVPacket pkt;
  570.     pkt.data = NULL;
  571.     pkt.size = 0;
  572.     av_init_packet(&pkt);
  573.     int i = 0;
  574.  
  575.     for (got_output = 1; got_output; i++)
  576.     {
  577.         ret = avcodec_encode_audio2(c, &pkt, NULL, &got_output);
  578.         if (ret < 0)
  579.         {
  580.             fprintf(stderr, "error encoding frame\n");
  581.             exit(1);
  582.         }
  583.         static int64_t tempPts = 0;
  584.         static int64_t tempDts = 0;
  585.         /* If size is zero, it means the image was buffered. */
  586.         if (got_output)
  587.         {
  588.             if (pkt.pts != AV_NOPTS_VALUE)
  589.                 pkt.pts = av_rescale_q(pkt.pts, st->codec->time_base, st->time_base);
  590.             if (pkt.dts != AV_NOPTS_VALUE)
  591.                 pkt.dts = av_rescale_q(pkt.dts, st->codec->time_base, st->time_base);
  592.             if (c && c->coded_frame && c->coded_frame->key_frame)
  593.                 pkt.flags |= AV_PKT_FLAG_KEY;
  594.  
  595.             pkt.stream_index = st->index;
  596.             /* Write the compressed frame to the media file. */
  597.             ret = av_interleaved_write_frame(oc, &pkt);
  598.         }
  599.         else
  600.         {
  601.             ret = 0;
  602.         }
  603.         av_free_packet(&pkt);
  604.     }
  605. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement