Skip to content

Commit

Permalink
MythUtil: add a --calctracklen option
Browse files Browse the repository at this point in the history
This command will decode a music track to determin it's exact length and will
then update the database and send a MUSIC_METADATA_CHANGED event if it changed.

Example:-
mythutil --calctracklen --songid='1234'
  • Loading branch information
Paul Harrison committed Feb 18, 2014
1 parent a9b8a86 commit 98c3f59
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 0 deletions.
5 changes: 5 additions & 0 deletions mythtv/programs/mythutil/commandlineparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,9 @@ void MythUtilCommandLineParser::LoadArguments(void)
<< add("--extractimage", "extractimage", false,
"Extract an embedded image from a tracks tag and cache it in the AlbumArt storage group", "")
->SetGroup("Metadata Reading/Writing")
<< add("--calctracklen", "calctracklen", false,
"Decode a track to determine its exact length", "")
->SetGroup("Metadata Reading/Writing")
);

// mpegutils.cpp
Expand Down Expand Up @@ -230,6 +233,8 @@ void MythUtilCommandLineParser::LoadArguments(void)
->SetChildOf("extractimage");
add("--imagetype", "imagetype", "", "Type of image to extract (front, back, cd, inlay, unknown)", "")
->SetChildOf("extractimage");
add("--songid", "songid", "", "ID of track to determine the length", "")
->SetChildOf("calctracklen");

// Generic Options used by more than one utility
addRecording();
Expand Down
125 changes: 125 additions & 0 deletions mythtv/programs/mythutil/musicmetautils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@
#include "musicfilescanner.h"
#include "musicutils.h"

extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
}

// mythutils headers
#include "commandlineparser.h"
#include "musicmetautils.h"
Expand Down Expand Up @@ -186,9 +191,129 @@ static int ScanMusic(const MythUtilCommandLineParser &cmdline)
return GENERIC_EXIT_OK;
}

static int CalcTrackLength(const MythUtilCommandLineParser &cmdline)
{
if (cmdline.toString("songid").isEmpty())
{
LOG(VB_GENERAL, LOG_ERR, "Missing --songid option");
return GENERIC_EXIT_INVALID_CMDLINE;
}

int songID = cmdline.toInt("songid");

MusicMetadata *mdata = MusicMetadata::createFromID(songID);
if (!mdata)
{
LOG(VB_GENERAL, LOG_ERR, QString("Cannot find metadata for trackid: %1").arg(songID));
return GENERIC_EXIT_NOT_OK;
}

QString musicFile = mdata->getLocalFilename();

if (musicFile.isEmpty() || !QFile::exists(musicFile))
{
LOG(VB_GENERAL, LOG_ERR, QString("Cannot find file for trackid: %1").arg(songID));
return GENERIC_EXIT_NOT_OK;
}

av_register_all();

AVFormatContext *inputFC = NULL;
AVInputFormat *fmt = NULL;

// Open track
LOG(VB_GENERAL, LOG_DEBUG, QString("CalcTrackLength: Opening '%1'")
.arg(musicFile));

QByteArray inFileBA = musicFile.toLocal8Bit();

int ret = avformat_open_input(&inputFC, inFileBA.constData(), fmt, NULL);

if (ret)
{
LOG(VB_GENERAL, LOG_ERR, "CalcTrackLength: Couldn't open input file" +
ENO);
return GENERIC_EXIT_NOT_OK;
}

// Getting stream information
ret = avformat_find_stream_info(inputFC, NULL);

if (ret < 0)
{
LOG(VB_GENERAL, LOG_ERR,
QString("CalcTrackLength: Couldn't get stream info, error #%1").arg(ret));
avformat_close_input(&inputFC);
inputFC = NULL;
return GENERIC_EXIT_NOT_OK;;
}

uint duration = 0;
long long time = 0;

for (uint i = 0; i < inputFC->nb_streams; i++)
{
AVStream *st = inputFC->streams[i];
char buf[256];

avcodec_string(buf, sizeof(buf), st->codec, false);

switch (inputFC->streams[i]->codec->codec_type)
{
case AVMEDIA_TYPE_AUDIO:
{
AVPacket pkt;
av_init_packet(&pkt);

while (av_read_frame(inputFC, &pkt) >= 0)
{
if (pkt.stream_index == (int)i)
time = time + pkt.duration;

av_free_packet(&pkt);
}

duration = time * av_q2d(inputFC->streams[i]->time_base);
break;
}

default:
LOG(VB_GENERAL, LOG_ERR,
QString("Skipping unsupported codec %1 on stream %2")
.arg(inputFC->streams[i]->codec->codec_type).arg(i));
break;
}
}

// Close input file
avformat_close_input(&inputFC);
inputFC = NULL;

if (mdata->Length() / 1000 != duration)
{
LOG(VB_GENERAL, LOG_INFO, QString("The length of this track in the database was %1s "
"it is now %2s").arg(mdata->Length() / 1000).arg(duration));

// update the track length in the database
mdata->setLength(duration * 1000);
mdata->dumpToDatabase();

// tell any clients that the metadata for this track has changed
gCoreContext->SendMessage(QString("MUSIC_METADATA_CHANGED %1").arg(songID));
}
else
{
LOG(VB_GENERAL, LOG_INFO, QString("The length of this track is unchanged %1s")
.arg(mdata->Length() / 1000));
}

return GENERIC_EXIT_OK;
}

void registerMusicUtils(UtilMap &utilMap)
{
utilMap["updatemeta"] = &UpdateMeta;
utilMap["extractimage"] = &ExtractImage;
utilMap["scanmusic"] = &ScanMusic;
utilMap["calctracklen"] = &CalcTrackLength;
}

0 comments on commit 98c3f59

Please sign in to comment.